这是两个月前写的,看能不能搬运过来……

动态树是一类维护森林连通性的问题(已纠正,感谢ZQC巨佬),目前最(wo)常(zhi)见(hui)的动态树就是LCT(Link-Cut-Tree),然而LCT似乎是处理路径的,处理子树可能力不足。据说有一种称为Top Tree数据结构,可以处理所有。但是学不动了Orz
LCT中最主要的是Access操作,Access(u)操作的含义是,从当前的节点u向他所在的根节点连一条重路径,这是相当于把沿路的重路径全都断开,重新拉一条从u到根的重路径。
makeroot(x)操作:
若想让u成为当前树的根节点,则可以先access(u),再splay(u),把u转为当前splay的根节点。因为splay维护的是深度,所以u没有右儿子(没有比u还要深的点,因为重链定义),所以换根就相当于一次区间翻转,交换左右子树即完成区间翻转。此时就可以打标记了。
所以,makeroot=access+splay+rev
还有一个isroot操作,超级简单,就是判断这是不是一条重路径的根,只要他的fa指针指向的节点的左右子树都不是他(证明此时这是一条虚边),那么这就是一棵子树的根节点。
link(x,y)操作:
在u和v之间连边,可以makeroot(u),再让u的父亲为v,这就相当于v本身是一棵splay,而u和v之间连了条轻边。
cut(u,v)操作:
断开u和v之间的边,可以先makeroot(u),再access(v),再splay(v),此时v的左儿子必定为u,于是断开v和v的左儿子即可。
至于翻转标记的传递,就是跟Splay一样就行了。
但标记下放有一个问题。因为splay是时时刻刻在分裂与合并的,因为要动态维护每条重链,所以在splay之前,要先把根节点到当前节点全部下放一遍标记,防止标记下放不完全。
split(x,y)操作:
split相当于把两个子树分开,考虑到我们cut的时候第一步也是分开,所以

$split=makeroot(u)+access(v)+splay(v)$
然后还要保存一些轻边(虚边),对于轻边我们需要单独记录处理。在原树上,当前重链的顶端节点与他的父亲的边即为轻边,如果不记录,树将是不完整的。
具体到代码实现,可以是当前splay的根节点的父亲即为当前splay上面的那个重链所在的splay上的点,但上面的splay的儿子并不指向当前splay的父亲,即为用splay的根节点的父亲来存储轻边。
动态树的主要时间消耗在Access上,而Access的时间复杂度是

$O(nlogn)$
好像最后在UOJ群里看到一句话:
*树剖能做的,动态树都能做,只不过有的东西动态树做起来比树剖烦的多*
好像超级有道理,因为我写的维护子树size,树剖的话天生自带,但是LCT每次Access跳轻重边的时候都要交换,超级烦。
下面是这几天做的一点题目:
1.洞穴勘测
裸的连通性询问。

 #include<bits/stdc++.h>
#define N 10005
#define inf 1000000007
using namespace std;
int n,m;
struct Link_Cut_Tree{
int fa[N],c[N][],q[N],top;bool rev[N];
Link_Cut_Tree(){
top=;memset(fa,,sizeof(fa));
memset(c,,sizeof(c));
memset(rev,,sizeof(rev));
}
inline bool isroot(int x){return c[fa[x]][]!=x&&c[fa[x]][]!=x;}
inline void pushdown(int x){
int l=c[x][],r=c[x][];
if(rev[x]){
rev[x]^=;rev[l]^=;rev[r]^=;
swap(c[x][],c[x][]);
}
}
void rotate(int x){
int y=fa[x],z=fa[y],l,r;
l=(c[y][]==x);r=l^;
if(!isroot(y))c[z][c[z][]==y]=x;
fa[c[x][r]]=y;fa[y]=x;fa[x]=z;
c[y][l]=c[x][r];c[x][r]=y;
}
void splay(int x){
int top=;q[++top]=x;
for(int i=x;!isroot(i);i=fa[i])q[++top]=fa[i];
while(top)pushdown(q[top--]);
while(!isroot(x)){
int y=fa[x],z=fa[y];
if(!isroot(y)){
if(c[y][]==x^c[z][]==y)rotate(x);else rotate(y);
}
rotate(x);
}
}
void access(int x){for(int t=;x;t=x,x=fa[x])splay(x),c[x][]=t;}
void makeroot(int x){access(x);splay(x);rev[x]^=;}
void link(int x,int y){makeroot(x);fa[x]=y;splay(x);}
void split(int x,int y){makeroot(x);access(y);splay(y);}
void cut(int x,int y){split(x,y);c[y][]=fa[x]=;}
int find(int x){
access(x);splay(x);int y=x;while(c[y][])y=c[y][];return y;
}
}T;
inline int read(){
int x=,f=;char ch;
do{ch=getchar();if(ch=='-')f=-;}while(ch<''||ch>'');
do{x=x*+ch-'';ch=getchar();}while(ch>=''&&ch<='');
return f*x;
}
int main(){
char s[];int x,y;
n=read();m=read();
for(int i=;i<=m;i++){
scanf("%s",s);
x=read();y=read();
if(s[]=='C')T.link(x,y);
if(s[]=='D')T.cut(x,y);
if(s[]=='Q'){
int xx=T.find(x),yy=T.find(y);
if(xx==yy)puts("Yes");else puts("No");
}
}
return ;
}

2.bzoj1180 OTOCI
修改,连边,区间权值合。
其实可以先读入所有的边得到最后的树,然后离线树剖,用并查集维护边就行了
本蒟蒻还是写了Link-Cut-Tree

 #include<bits/stdc++.h>
#define N 30005
#define inf 1000000000
#define yql 1000000007
#define ll long long
using namespace std;
int q,n;
struct Link_Cut_Tree{
int c[N][],fa[N],sumv[N],val[N],q[N],top[N];
bool rev[N];
void pushup(int x){
int l=c[x][],r=c[x][];sumv[x]=sumv[l]+sumv[r]+val[x];
}
void pushdown(int x){
int l=c[x][],r=c[x][];
if(rev[x]){
rev[x]^=;rev[r]^=;rev[l]^=;
swap(c[x][],c[x][]);
}
}
bool isroot(int x){return c[fa[x]][]!=x&&c[fa[x]][]!=x;}
void rotate(int x){
int y=fa[x],z=fa[y],l,r;
l=(c[y][]==x);r=l^;
if(!isroot(y))c[z][c[z][]==y]=x;
fa[c[x][r]]=y;fa[y]=x;fa[x]=z;
c[y][l]=c[x][r];c[x][r]=y;
pushup(y);pushup(x);
}
void splay(int x){
int top=;q[++top]=x;
for(int i=x;!isroot(i);i=fa[i])q[++top]=fa[i];
while(top)pushdown(q[top--]);
while(!isroot(x)){
int y=fa[x],z=fa[y];
if(!isroot(y)){
if(c[y][]==x^c[z][]==y)rotate(x);else rotate(y);
}
rotate(x);
}
}
void access(int x){for(int t=;x;t=x,x=fa[x])splay(x),c[x][]=t,pushup(x);}
void makeroot(int x){access(x);splay(x);rev[x]^=;}
void link(int x,int y){makeroot(x);fa[x]=y;}
void split(int x,int y){makeroot(x);access(y);splay(y);}
void cut(int x,int y){split(x,y);c[y][]=fa[x]=;}
int find(int x){
access(x);splay(x);int y=x;while(c[y][])y=c[y][];return y;
}
}T;
inline int read(){
int f=,x=;char ch;
do{ch=getchar();if(ch=='-')f=-;}while(ch<''||ch>'');
do{x=x*+ch-'';ch=getchar();}while(ch>=''&&ch<='');
return f*x;
}
int main(){
n=read();
for(int i=;i<=n;i++){T.sumv[i]=read();T.val[i]=T.sumv[i];}
q=read();char s[];
while(q--){
scanf("%s",s);int x=read(),y=read();
if(s[]=='b'){
int xx=T.find(x),yy=T.find(y);
if(xx==yy)puts("no");
else puts("yes"),T.link(x,y);
}
if(s[]=='p')T.makeroot(x),T.val[x]=y,T.pushup(x);
if(s[]=='e'){
int xx=T.find(x),yy=T.find(y);
if(xx!=yy)puts("impossible");
else{
T.makeroot(x);T.access(y);T.splay(y);
printf("%d\n",T.sumv[y]);
}
}
}
return ;
}

3.NOI2014 膜法森林
考虑Kruskal求出最小生成树,每次加,如果当前的边成环,那么就在之前的边里找一个最大权的cut掉。
维护连通性,cut边,最大值询问,LCT很擅长啦~

 #include<bits/stdc++.h>
#define inf 1000000007
#define N 200005
using namespace std;
int n,m,cnt,_=inf;
int f[N];
int find(int x){return x==f[x]?x:f[x]=find(f[x]);}
struct Edge{
int u,v,w,c;
bool operator<(const Edge &x)const{return w<x.w;}
}G[*N]; struct Link_Cut_Tree{
int c[N][],fa[N],q[N],rev[N],top;
int maxv[N],val[N];
inline void pushup(int x){
int l=c[x][],r=c[x][];
maxv[x]=x;
if(val[maxv[l]]>val[maxv[x]])maxv[x]=maxv[l];
if(val[maxv[r]]>val[maxv[x]])maxv[x]=maxv[r];
}
Link_Cut_Tree(){top=;memset(rev,,sizeof(rev));}
bool isroot(int x){return c[fa[x]][]!=x&&c[fa[x]][]!=x;}
void pushdown(int x){
int l=c[x][],r=c[x][];
if(rev[x]){
rev[l]^=;rev[r]^=;rev[x]^=;
swap(c[x][],c[x][]);
}
}
void rotate(int x){
int y=fa[x],z=fa[y],l,r;
l=(c[y][])==x;r=l^;
if(!isroot(y))c[z][c[z][]==y]=x;
fa[c[x][r]]=y;fa[y]=x;fa[x]=z;
c[y][l]=c[x][r];c[x][r]=y;
pushup(y);pushup(x);
}
void splay(int x){
int top=;q[++top]=x;
for(int i=x;!isroot(i);i=fa[i])q[++top]=fa[i];
while(top)pushdown(q[top--]);
while(!isroot(x)){
int y=fa[x],z=fa[y];
if(!isroot(y)){
if(c[y][]==x^c[z][]==y)rotate(x);else rotate(y);
}
rotate(x);
}
}
void access(int x){for(int t=;x;t=x,x=fa[x])splay(x),c[x][]=t,pushup(x);}
void makeroot(int x){access(x);splay(x);rev[x]^=;}
void link(int x,int y){makeroot(x);fa[x]=y;splay(x);}
void split(int x,int y){makeroot(x);access(y);splay(y);}
void cut(int x,int y){split(x,y);c[y][]=fa[x]=;pushup(y);}
int find(int x){access(x);splay(x);int y=x;while(c[y][])y=c[y][];return y;}
int querymax(int x,int y){split(x,y);return maxv[y];}
};
Link_Cut_Tree T;
inline int read(){
int f=,x=;char ch;
do{ch=getchar();if(ch=='')f=-;}while(ch<''||ch>'');
do{x=x*+ch-'';ch=getchar();}while(ch>=''&&ch<='');
return f*x;
}
int main(){
n=read();m=read();
for(int i=;i<=n+;i++)f[i]=i;
for(int i=;i<=m;i++){
G[i].u=read(),G[i].v=read(),G[i].w=read();G[i].c=read();
}
sort(G+,G+m+);
int tot=;
for(int i=;i<=m;i++){
int u=G[i].u,v=G[i].v,w=G[i].w,c=G[i].c;
if(find(u)==find(v)){
int t=T.querymax(u,v);
if(T.val[t]>G[i].c){
T.cut(t,G[t-n].u);
T.cut(t,G[t-n].v);
}
else {
if(find()==find(n))_=min(_,G[i].w+T.val[T.querymax(,n)]);
continue;
}
}
else f[find(u)]=find(v);
T.val[n+i]=G[i].c;T.maxv[n+i]=n+i;
T.link(u,n+i);T.link(v,n+i);
if(find()==find(n))_=min(_,G[i].w+T.val[T.querymax(,n)]);
}
if(_==inf)puts("-1");else printf("%d\n",_);
return ;
}

4.uoj 共价大爷游长沙
%%%%毛爷爷,不看题解不会系列。
这题做的极其艰辛:
1.zcy:我怎么维护子树size啊…………啊………………
想了半个下午,我好像会了!去机房写!
2.zcy:我的权值怎么这么小啊,都是几十几十的东西……
wori,随机数种子选的有毒?我去uoj上找一个吧……
3.zcy:我的link怎么权值改的那么鬼啊?我看看……
wori,cut写错了,mdzz。
代码准确度啊……

#include<bits/stdc++.h>
#define N 300100
using namespace std;
int n,m,x,y,z;
struct Link_Cut_Tree{
int c[N][],q[N],fa[N],size[N],top,rev[N],val[N],sumv[N];
int a[N],b[N],w[N],sum;
inline bool isroot(int x){return fa[x]==||c[fa[x]][]!=x&&c[fa[x]][]!=x;}
inline void pushdown(int x){
int l=c[x][],r=c[x][];
if(rev[x]){
rev[l]^=;rev[r]^=;rev[x]^=;
swap(c[x][],c[x][]);
}
}
void pushall(int x){
if(!isroot(x))pushall(fa[x]);pushdown(x);
}
inline void pushup(int x){
sumv[x] = val[x]^sumv[c[x][]]^sumv[c[x][]];
}
void rotate(int x){
int y = fa[x],g=fa[y],ch=c[y][]==x;
if (!isroot(y))c[g][c[g][]==y]=x;
c[y][ch]=c[x][!ch],fa[c[y][ch]]=y;
fa[y] =x,fa[x]=g,c[x][!ch] = y;
pushup(y);
}
void splay(int x){
int top=;q[++top]=x;
for(int i=x;!isroot(i);i=fa[i])q[++top]=fa[i];
while(top)pushdown(q[top--]);
while(!isroot(x)){
int y=fa[x],z=fa[y];
if(!isroot(y)){
if(c[y][]==x^c[z][]==y)rotate(x);else rotate(y);
}
rotate(x);
}
pushup(x);
}
void access(int x){
for(int t=;x;t=x,x=fa[x]){
splay(x);val[x]^=sumv[t]^sumv[c[x][]];
c[x][]=t;pushup(x);
}
}
void makeroot(int x){access(x);splay(x);rev[x]^=;}
void link(int x,int y){
makeroot(x);makeroot(y);fa[x]=y;val[y]^=sumv[x];pushup(y);
}
void split(int x,int y){makeroot(x);access(y);splay(y);}
void cut(int x,int y){
makeroot(y);access(y);splay(x);fa[x]=;val[y]^=sumv[x];pushup(y);
}
void change(int x,int v){access(x);splay(x);val[x]^=v;pushup(x);}
}T; struct Edge{
int u;int v;int w;
Edge(int a=,int b=,int c=){u=a;v=b;w=c;}
}G[*N];
inline int read(){
int x=,f=;char ch;
do{ch=getchar();if(ch=='-')f=-;}while(ch<''||ch>'');
do{x=x*+ch-'';ch=getchar();}while(ch>=''&&ch<='');
return f*x;
}
int main(){
int id;
id=read();n=read();m=read();
srand(time(NULL));
for(int i=;i<n;i++){
x=read(),y=read();
T.link(x,y);
}x=;y=;
int tot=,res=;
while(m--){
int opt=read(),x,y,u,v;
if(opt==){
x=read();y=read();u=read();v=read();
T.cut(x,y);T.link(u,v);//printf("%d\n",T.val[v]);
}
else if(opt==){
int k=rand();
x=read(),y=read();while(!k)k=rand();
G[++tot]=Edge(x,y,k);res^=k;
T.change(x,k);T.change(y,k);
//printf("%d\n",T.val[y]);
}
else if(opt==){
x=read();
res^=G[x].w;
T.change(G[x].u,G[x].w);T.change(G[x].v,G[x].w);
}
else if(opt==){
x=read();y=read();
T.makeroot(x);T.access(y);
if(T.val[y]==res)puts("YES");
else puts("NO");
}
//printf("%d\n",res);printf("%d\n",T.val[y]);
}
return ;
}

不开心,这个快把我写死的LCT居然只有100行
5.ZJOI2012 网络
这题如果单看每种颜色,我们只要建一个LCT就能轻松水过去,无非是要加个cnt
但是颜色多怎么办?考虑颜色种类很小,我们多建几个LCT不就行了么?

 #include<bits/stdc++.h>
#define N 10005
#define M 100005
using namespace std;
int n, m, c, k, u, v, w, op, x,val[N];
struct Link_Cut_Tree{
int c[N][],fa[N],rev[N],maxv[N],cnt[N],q[N];
inline void pushup(int x){
maxv[x]=val[x];int l=c[x][],r=c[x][];
if(l)maxv[x]=max(maxv[x],maxv[l]);
if(r)maxv[x]=max(maxv[x],maxv[r]);
}
inline void pushdown(int x){
int l=c[x][],r=c[x][];
if(rev[x]){
rev[l]^=;rev[r]^=;rev[x]^=;
swap(c[x][],c[x][]);
}
}
bool isroot(int x){return c[fa[x]][]!=x&&c[fa[x]][]!=x;}
void rotate(int x){
int y=fa[x],z=fa[y],l,r;
l=(c[y][])==x;r=l^;
if(!isroot(y))c[z][c[z][]==y]=x;
fa[c[x][r]]=y;fa[y]=x;fa[x]=z;
c[y][l]=c[x][r];c[x][r]=y;
pushup(y);pushup(x);
}
void splay(int x){
int top=;q[++top]=x;
for(int i=x;!isroot(i);i=fa[i])q[++top]=fa[i];
while(top)pushdown(q[top--]);
while(!isroot(x)){
int y=fa[x],z=fa[y];
if(!isroot(y)){
if(c[y][]==x^c[z][]==y)rotate(x);else rotate(y);
}
rotate(x);
}
}
void access(int x){for(int t=;x;t=x,x=fa[x])splay(x),c[x][]=t,pushup(x);}
void makeroot(int x){access(x);splay(x);rev[x]^=;}
void link(int x,int y){cnt[x]++;cnt[y]++;makeroot(x);fa[x]=y;splay(x);}
void split(int x,int y){makeroot(x);access(y);splay(y);}
void cut(int x,int y){split(x,y);cnt[x]--;cnt[y]--;c[y][]=fa[x]=;pushup(y);}
int find(int x){access(x);splay(x);int y=x;while(c[y][])y=c[y][];return y;}
int querymax(int x,int y){split(x,y);return maxv[y];}
}lct[];
inline int read(){
int f=,x=;char ch;
do{ch=getchar();if(ch=='')f=-;}while(ch<''||ch>'');
do{x=x*+ch-'';ch=getchar();}while(ch>=''&&ch<='');
return f*x;
}
struct Edge{
int u,v;
bool operator<(const Edge &x)const{if(u!=x.u)return u<x.u;
else return v<x.v;}
};
map<Edge,int> mp;
int main(){
n=read();m=read();c=read();k=read();
for(int i=;i<=n;i++)val[i]=read();
for(int i=;i<=m;i++){
int u=read(),v=read(),w=read();
w++;
Edge e1=(Edge){u,v},e2=(Edge){v,u};
mp[e1]=mp[e2]=w;
lct[w].link(u,v);
}
while(k--){
int opt=read();
if(opt==){
int x=read(),w=read();
val[x]=w;
for(int i=;i<=c;i++)lct[i].splay(x);
}
else if(opt==){
int u=read(),v=read(),w=read();
w++;
Edge a=(Edge){u,v},b=(Edge){v,u};
if(!mp.count(a)){
puts("No such edge.");continue;
}
int xxx=mp[a];
if(xxx==w){
puts("Success.");continue;
}
if(lct[w].cnt[u]>=||lct[w].cnt[v]>=){
puts("Error 1.");continue;
}
if(lct[w].find(u)==lct[w].find(v)){
puts("Error 2.");continue;
}
puts("Success.");
lct[xxx].cut(u,v);lct[w].link(u,v);
mp[a]=mp[b]=w;
}else{
int w=read(),u=read(),v=read();
w++;
if(lct[w].find(u)!=lct[w].find(v)){
puts("-1");continue;
}
printf("%d\n",lct[w].querymax(u,v));
}
}
return ;
}

【学习笔记】动态树Link-Cut-Tree的更多相关文章

  1. 动态树(Link Cut Tree) :SPOJ 375 Query on a tree

    QTREE - Query on a tree #number-theory You are given a tree (an acyclic undirected connected graph) ...

  2. 【学习笔记】LCT link cut tree

    大概就是供自己复习的吧 1. 细节讲解 安利两篇blog: Menci 非常好的讲解与题单 2.模板 把 $ rev $ 和 $ pushdown $ 的位置记清 #define lc son[x][ ...

  3. 学习笔记-动态树Link-Cut-Tree

    --少年你有梦想吗? --少年你听说过安利吗? 安利一个集训队讲解:http://wenku.baidu.com/view/75906f160b4e767f5acfcedb 关于动态树问题,有多种方法 ...

  4. LCT总结——概念篇+洛谷P3690[模板]Link Cut Tree(动态树)(LCT,Splay)

    为了优化体验(其实是强迫症),蒟蒻把总结拆成了两篇,方便不同学习阶段的Dalao们切换. LCT总结--应用篇戳这里 概念.性质简述 首先介绍一下链剖分的概念(感谢laofu的讲课) 链剖分,是指一类 ...

  5. Link Cut Tree学习笔记

    从这里开始 动态树问题和Link Cut Tree 一些定义 access操作 换根操作 link和cut操作 时间复杂度证明 Link Cut Tree维护链上信息 Link Cut Tree维护子 ...

  6. P3690 【模板】Link Cut Tree (动态树)

    P3690 [模板]Link Cut Tree (动态树) 认父不认子的lct 注意:不 要 把 $fa[x]$和$nrt(x)$ 混 在 一 起 ! #include<cstdio> v ...

  7. 【刷题】洛谷 P3690 【模板】Link Cut Tree (动态树)

    题目背景 动态树 题目描述 给定n个点以及每个点的权值,要你处理接下来的m个操作.操作有4种.操作从0到3编号.点从1到n编号. 0:后接两个整数(x,y),代表询问从x到y的路径上的点的权值的xor ...

  8. LuoguP3690 【模板】Link Cut Tree (动态树) LCT模板

    P3690 [模板]Link Cut Tree (动态树) 题目背景 动态树 题目描述 给定n个点以及每个点的权值,要你处理接下来的m个操作.操作有4种.操作从0到3编号.点从1到n编号. 0:后接两 ...

  9. 学习笔记:Link Cut Tree

    模板题 原理 类似树链剖分对重儿子/长儿子剖分,Link Cut Tree 也做的是类似的链剖分. 每个节点选出 \(0 / 1\) 个儿子作为实儿子,剩下是虚儿子.对应的边是实边/虚边,虚实时可以进 ...

  10. LG3690 【模板】Link Cut Tree (动态树)

    题意 给定n个点以及每个点的权值,要你处理接下来的m个操作.操作有4种.操作从0到3编号.点从1到n编号. 0:后接两个整数(x,y),代表询问从x到y的路径上的点的权值的xor和.保证x到y是联通的 ...

随机推荐

  1. 【bzoj5049】[Lydsy九月月赛]导航系统 并查集+双向BFS最短路

    题目描述 给你一张 $n$ 个点 $m$ 条边的随机图,边权为1.$k$ 次询问两点间最短路,不连通则输出-1. 输入 第一行包含3个正整数n,m,k(2<=n<=100000,1< ...

  2. 【bzoj4641】基因改造 特殊匹配条件的KMP

    题目描述 如果两个长度相等的字符串,如果存在一种字符的一一映射,使得第一个字符串的所有字符经过映射后与第二个字符串相同,那么就称它们“匹配”.现在给出两个串,求第一个字符串所有长度等于第二个字符串的长 ...

  3. 51nod 1304 字符串的相似度(exkmp)

    拓展kmp裸题 自己跟自己匹配即可 模板测试=v= #include <iostream> #include <cstring> using namespace std; ; ...

  4. 【hackerrank】Week of Code 30

    Candy Replenishing Robot Find the Minimum Number 直接模拟 Melodious password dfs输出方案 Poles 题意:有多个仓库,只能从后 ...

  5. Linux相关——手写测试程序

    由于本人太弱,,,不会lemon,,,也不会在ubuntu下安装lemon,所以我选择手写测试程序emmmm 首先要写这个东西我们要先知道对拍怎么写. ; i <= ; i++) { syste ...

  6. ZOJ1994 & POJ2396:Budget——题解

    http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=1994 http://poj.org/problem?id=2396 题目大 ...

  7. BZOJ2659 [Beijing wc2012]算不出的算式 【数形结合】

    题目链接 BZOJ2659 题解 真没想到,, 观察式子 \[\sum\limits_{k = 1}^{\frac{p - 1}{2}} \lfloor \frac{kq}{p} \rfloor\] ...

  8. UVA.11636 Hello World! (思维题)

    UVA.11636 Hello World! (思维题) 题意分析 这题挺水的,还是错了几发. QWQ. 有一个同学打了一行hello world,现在他想打n行hello world,请问最少复制粘 ...

  9. python多进程之Process

    由于fork创建进程不能在windows系统上使用,所以产生了multiprocessing.Process Process可以直接实例化然后用start调用,需要指定新的进程执行的函数,用元组的方式 ...

  10. 题解【poj2774 Long Long Message】

    Description 求两个串的最长连续公共字串 Solution 后缀数组入门题吧 把两个串连在一起,中间加一个分隔符,然后跑一遍后缀数组,得到 height 和 sa 一个 height[i] ...