BZOJ2631: tree
题解: LCT 类似维护一次函数 a*x+b 的双标记
/************************************************************** Problem: 2631 User: c20161007 Language: C++ Result: Accepted Time:21336 ms Memory:9352 kb ****************************************************************/ #include <iostream> #include <cstdio> #include <vector> #define ll unsigned int const int MAXN=1e5+10; const int lth=51061; using namespace std; //ll readll(){ // ll x=0,f=1;char ch=getchar(); // while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} // while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} // return x*f; //} int readint(){ int x=0,f=1;char ch=getchar(); while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();} while(isdigit(ch))x=x*10+ch-'0',ch=getchar(); return f*x; } int ch[MAXN][2],pre[MAXN],rt[MAXN],size[MAXN],n,q; ll key[MAXN],sum[MAXN],add[MAXN],res[MAXN],mul[MAXN]; void Treavel(int x) { if(x) { // cout<<x<<endl; Treavel(ch[x][0]); printf("结点%2d:左儿子 %2d 右儿子 %2d 父结点 %2d size=%2d,key=%2d\n",x,ch[x][0],ch[x][1],pre[x],size[x],key[x]); Treavel(ch[x][1]); } } void debug(int rp) { printf("root:%d\n",rp); Treavel(rp); } void update(int r,ll vul1,ll vul2){ if(!r) return ; sum[r]=((sum[r]*vul1)%lth+(size[r]*vul2)%lth)%lth; key[r]=((vul1*key[r])%lth+vul2)%lth; mul[r]=(mul[r]*vul1)%lth; add[r]=((add[r]*vul1)%lth+vul2)%lth; } void update_add(int r,ll vul){ if(!r) return ; key[r]=(vul+key[r])%lth; sum[r]=(sum[r]+1ll*size[r]*vul)%lth; add[r]=(add[r]+vul)%lth; } void update_mul(int r,ll vul){ if(!r) return ; key[r]=(key[r]*vul)%lth; sum[r]=(sum[r]*vul)%lth; mul[r]=(mul[r]*vul)%lth; add[r]=(add[r]*vul)%lth; } void update_res(int r){ if(!r) return ; swap(ch[r][0],ch[r][1]); res[r]^=1; } void push(int x){ if(res[x]){ update_res(ch[x][0]); update_res(ch[x][1]); res[x]^=1; } update(ch[x][0],mul[x],add[x]); update(ch[x][1],mul[x],add[x]); mul[x]=1,add[x]=0; } void up(int x){ size[x]=size[ch[x][0]]+size[ch[x][1]]+1; sum[x]=(sum[ch[x][0]]+sum[ch[x][1]]+key[x])%lth; } void P(int r){ if(!rt[r]) P(pre[r]); push(r); } void rotate(int x,int kind){ int y=pre[x]; ch[y][!kind]=ch[x][kind]; pre[ch[x][kind]]=y; if(rt[y]) rt[y]=0,rt[x]=1; else ch[pre[y]][ch[pre[y]][1]==y]=x; pre[x]=pre[y];ch[x][kind]=y;pre[y]=x; up(y); } void splay(int x){ P(x); //cout<<x<<"-----"<<rt[x]<<endl; while(!rt[x]){ if(rt[pre[x]]) rotate(x,ch[pre[x]][0]==x); else{ int y=pre[x];int kind=ch[pre[y]][0]==y; if(ch[y][kind]==x) rotate(x,!kind),rotate(x,kind); else rotate(y,kind),rotate(x,kind); } } up(x); } void access(int x){ int y=0; //cout<<x<<endl; //cout<<pre[1]<<"-----"<<endl; // cout<<x<<" "<<pre[x]<<endl; while(x){ splay(x); //debug(x); //cout<<x<<"------"<<y<<endl; if(ch[x][1]) rt[ch[x][1]]=1,pre[ch[x][1]]=x,ch[x][1]=0; ch[x][1]=y; up(x); if(y) rt[y]=0,pre[y]=x; y=x;x=pre[x]; // cout<<x<<" "<<y<<endl; } //debug(1); return ; } void mroot(int x){ access(x);//debug(x); splay(x);//debug(x); //cout<<pre[1]<<"====="<<endl; //debug(x); update_res(x); //up(x); return ; } void operator_add(int u,int v,ll vul){ mroot(u);access(v);splay(u); update_add(u,vul); return ; } void operator_chong(int u1,int v1,int u2,int v2){ mroot(u1);access(v1);splay(v1); ch[v1][0]=0;up(v1); pre[u1]=pre[v1]=0;rt[u1]=rt[v1]=1; mroot(u2);pre[u2]=v2; } void operator_mul(int u,int v,ll vul){ //cout<<u<<" "<<v<<endl; // cout<<u<<" "<<v<<" "<<pre[u]<<" "<<pre[v]<<endl; // debug(u);debug(v); mroot(u); //debug(u); // cout<<rt[v]<<endl; access(v);//debug(v); splay(u); update_mul(u,vul); } int operator_querty(int u,int v){ //cout<<pre[u]<<" "<<pre[v]<<endl; //if(u==v) return key[u]%lth; mroot(u);//debug(u); //cout<<pre[1]<<"------"<<endl; access(v);//debug(v); splay(u); // debug(u); return sum[u]%lth; } vector<int>vec[MAXN]; void dfs(int v,int fa){ pre[v]=fa; for(int i=0;i<vec[v].size();i++){ if(vec[v][i]!=fa) dfs(vec[v][i],v); } } int main(){ ios::sync_with_stdio(false); n=readint();q=readint(); for(int i=1;i<=n;i++){ ch[i][0]=ch[i][1]=pre[i]=add[i]=res[i]=0; size[i]=rt[i]=key[i]=sum[i]=mul[i]=1; } char ch;int u,v,u1,v1;ll x; for(int i=1;i<n;i++){ u=readint();v=readint(); vec[u].push_back(v);vec[v].push_back(u); } dfs(1,0); for(int i=1;i<=q;i++){ scanf(" %c",&ch);u=readint();v=readint(); if(ch=='+'){ scanf("%d\n",&x);operator_add(u,v,x%lth); } else if(ch=='-'){ scanf("%d\n",&u1);scanf("%d\n",&v1); operator_chong(u,v,u1,v1); } else if(ch=='*'){ scanf("%d\n",&x); operator_mul(u,v,x%lth); } else printf("%d\n",operator_querty(u,v)); } return 0; }
2631: tree
Time Limit: 30 Sec Memory Limit: 128 MBSubmit: 5381 Solved: 1811
[Submit][Status][Discuss]
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