bzoj 2631: tree 动态树+常数优化
2631: tree
Time Limit: 30 Sec Memory Limit: 128 MBSubmit: 1716 Solved: 576
[Submit][Status]
Description
一棵n个点的树,每个点的初始权值为1。对于这棵树有q个操作,每个操作为以下四种操作之一:
+ u v c:将u到v的路径上的点的权值都加上自然数c;
- u1 v1 u2 v2:将树中原有的边(u1,v1)删除,加入一条新边(u2,v2),保证操作完之后仍然是一棵树;
* u v c:将u到v的路径上的点的权值都乘上自然数c;
/ u v:询问u到v的路径上的点的权值和,求出答案对于51061的余数。
Input
第一行两个整数n,q
接下来n-1行每行两个正整数u,v,描述这棵树
接下来q行,每行描述一个操作
接下来n-1行每行两个正整数u,v,描述这棵树
接下来q行,每行描述一个操作
Output
对于每个/对应的答案输出一行
Sample Input
3 2
1 2
2 3
* 1 3 4
/ 1 1
1 2
2 3
* 1 3 4
/ 1 1
Sample Output
4
HINT
数据规模和约定
10%的数据保证,1<=n,q<=2000
另外15%的数据保证,1<=n,q<=5*10^4,没有-操作,并且初始树为一条链
另外35%的数据保证,1<=n,q<=5*10^4,没有-操作
100%的数据保证,1<=n,q<=10^5,0<=c<=10^4
动态树编的还是不熟练,这道题的模数是刚刚爆int的(51061^2==2607225721>2147483647),如果用long long 又要TLE,所以必须用unsigned int.
这道题涉及到动态树的路径操作,具体用法是通过make_root()access()将一个路径上所有点集中到一个splay中。
还有一点,就是这类支持区间加,乘的题,标记应即为x*mul+plus,即先下放mul,在下放plus
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<ctime> #include<cmath> #include<algorithm> #include<set> #include<map> #include<vector> #include<string> #include<queue> using namespace std; #ifdef WIN32 #define LL "%I64d" #else #define LL "%lld" #endif #define MAXN 110000 #define MAXT MAXN*2 #define MAXV MAXN*2 #define MAXE MAXV*2 #define INF 0x3f3f3f3f #define INFL 0x3f3f3f3f3f3f3f3fLL #define lch ch[now][0] #define rch ch[now][1] #define plus _plus #define MOD 51061//刚刚爆int typedef unsigned int qword; inline int nextInt() { char ch; int x=0; bool flag=false; do ch=(char)getchar(),flag=(ch=='-')?true:flag; while(ch<'0'||ch>'9'); do x=x*10+ch-'0'; while (ch=(char)getchar(),ch<='9' && ch>='0'); return x*(flag?-1:1); } int n,m; struct Edge { int np; Edge *next; }E[MAXE],*V[MAXV]; int tope=-1; int fa[MAXT]; int depth[MAXT]; inline void addedge(int x,int y) { E[++tope].np=y; E[tope].next=V[x]; V[x]=&E[tope]; } void dfs(int now) { Edge *ne; for (ne=V[now];ne;ne=ne->next) { if (ne->np==fa[now])continue; fa[ne->np]=now; depth[ne->np]=depth[now]+1; dfs(ne->np); } } //------------------------Link Cut Tree------------------------ int pnt[MAXT],ch[MAXT][2]; qword sum[MAXT],val[MAXT]; qword mult[MAXT],plus[MAXT]; bool flip[MAXT]; int stack[MAXT],tops=-1; int siz[MAXT]; void init() { int i; for (i=1;i<=n;i++) { pnt[i]=fa[i]; mult[i]=1; plus[i]=0; val[i]=sum[i]=1; flip[i]=false; siz[i]=1; } } inline bool is_root(int now)//是splay上的根 { return (!pnt[now]) || (ch[pnt[now]][0]!=now && ch[pnt[now]][1]!=now); } inline void up(int now) { sum[now]=(sum[lch]+sum[rch]+val[now])%MOD; siz[now]=(siz[lch]+siz[rch]+1)%MOD; } inline void reverse(int now) { if (!now)return; swap(ch[now][0],ch[now][1]); flip[now]^=1; } inline void make_multiply(int now,qword v)//对于一个splay的子树加标记下放 { mult[now]=mult[now]*v%MOD; plus[now]=plus[now]*v%MOD; sum[now]=sum[now]*v%MOD; val[now]=val[now]*v%MOD; } inline void make_plus(int now,qword v)//同make_multiply { plus[now]=(plus[now]+v)%MOD; sum[now]=(sum[now]+v*siz[now])%MOD; val[now]=(val[now]+v)%MOD; } inline void down(int now) { if (flip[now]) { reverse(ch[now][0]); reverse(ch[now][1]); flip[now]=false; } if (mult[now]!=1) { make_multiply(ch[now][0],mult[now]); make_multiply(ch[now][1],mult[now]); mult[now]=1; } if (plus[now]) { make_plus(ch[now][0],plus[now]); make_plus(ch[now][1],plus[now]); plus[now]=0; } } inline void rotate(int now) { int p=pnt[now],anc=pnt[p]; if (is_root(now))throw 1; int dir=ch[p][0]==now; pnt[now]=anc; if (!is_root(p))/**/ ch[anc][ch[anc][1]==p]=now; ch[p][1-dir]=ch[now][dir]; pnt[ch[now][dir]]=p; pnt[p]=now; ch[now][dir]=p; up(p); up(now); } void splay(int now) { int x=now; while (!is_root(x)) { stack[++tops]=x; x=pnt[x]; } stack[++tops]=x; do{ down(stack[tops--]); }while (tops>=0); if (is_root(now))return ;//先下放标记,否则access中自动接在其他点上面 while (!is_root(now)) { int p=pnt[now],anc=pnt[p]; if (is_root(p))//注意判断的对象 { rotate(now); }else { if ((ch[anc][0]==p) == (ch[p][0]==now)) { rotate(p); rotate(now); }else { rotate(now); rotate(now); } } } } void access(int now)//需要记忆! { int son=0; for (;now;now=pnt[son=now]) { splay(now); ch[now][1]=son; up(now); } // while (ch[now][0]) // now=ch[now][0]; // return now; } void make_root(int now) { access(now); splay(now); swap(ch[now][0],ch[now][1]); reverse(ch[now][0]); reverse(ch[now][1]); //reverse(now);//注意 } void cut(int x,int y) { make_root(x); access(y); splay(x); ch[x][ch[x][1]==y]=0; pnt[y]=0; up(x); up(y); } void link(int x,int y) { // access(y); splay(y); make_root(x); access(x); splay(x); pnt[x]=y; up(y); } void scan(int now) { if (!now)return ; down(now); scan(lch); printf("%d ",(int)val[now]); scan(rch); } int main() { //freopen("input.txt","r",stdin); //freopen("output.txt","w",stdout); int i; int x,y,z; int a,b,c,d; scanf("%d%d",&n,&m); for (i=1;i<n;i++) { x=nextInt();y=nextInt(); //scanf("%d%d",&x,&y); addedge(x,y); addedge(y,x); } scanf("\n"); dfs(1); init(); char opt; for (i=0;i<m;i++) { opt=(int)getchar(); //scanf("%c",&opt); if (opt=='+') { x=nextInt();y=nextInt();z=nextInt(); //scanf("%d%d%d\n",&x,&y,&z); z%=MOD; make_root(x); access(y); splay(y); make_plus(y,z); }else if (opt=='-') { a=nextInt();b=nextInt();c=nextInt();d=nextInt(); //scanf("%d%d%d%d\n",&a,&b,&c,&d); cut(a,b); link(c,d); }else if (opt=='*') { x=nextInt();y=nextInt();z=nextInt(); //scanf("%d%d%d\n",&x,&y,&z); z%=MOD; make_root(x); access(y); splay(y); make_multiply(y,z); }else if (opt=='/') { x=nextInt();y=nextInt(); //scanf("%d%d\n",&x,&y); make_root(x); access(y); splay(y); printf("%d\n",(int)sum[y]); } } return 0; }
by mhy12345(http://www.cnblogs.com/mhy12345/) 未经允许请勿转载
本博客已停用,新博客地址:http://mhy12345.xyz