bzoj 2631: tree

Time Limit: 30 Sec  Memory Limit: 128 MB
Submit: 2928  Solved: 975
[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行,每行描述一个操作

Output

  对于每个/对应的答案输出一行

Sample Input

3 2
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

题解:

  四种操作显然要用动态树来维护,对于+和*的操作,需要打标记,但是在标记下放的时候需要考虑先放+还是先放*的问题。

  假设现在树中有权值为x和权值为y的两个节点,y是x的父亲节点,要对它俩依次进行+a1 *b1 *b2 +a2这四种操作,由于y是x的父亲,所以只是对y打上标记,不会下放到x节点。x节点应该的值是:(x+a1)*b1*b2+a2=a1*b1*b2*x+a1*b1*b2+a2,令t1=a1*b1*b2 , t2=a1*b1*b2+a2,则原式可以写成:t1*x+t2 , 在这里t1即为乘法标记,t2即为加法标记,下放的方式就是 t1*x+t2的形式,从上面的式子可以看出,对于乘法标记了累计原则就是有加有乘,对于加法标记的原则是只乘不加。由此下放标记

  其余的就是动态树的常规操作。

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstdlib>
  4 #include<cstring>
  5 #include<cmath>
  6 #include<algorithm>
  7 #include<queue>
  8 #include<vector>
  9 using namespace std;
 10 typedef unsigned int UI;
 11 const UI maxn=200000;
 12 const UI mod=51061;
 13 UI N,Q;
 14 UI c[maxn][2],fa[maxn],key[maxn],size[maxn],sum[maxn],add[maxn],mul[maxn],st[maxn];
 15 char s[10];
 16 bool rev[maxn];
 17 bool isroot(UI x){
 18     return x!=c[fa[x]][0]&&x!=c[fa[x]][1];
 19 }
 20 void calc(UI x,UI a,UI b){//节点x,进行ax+b操作
 21     if(x==0) return;
 22     key[x]=((key[x]*a)%mod+b)%mod;
 23     sum[x]=((sum[x]*a)%mod+(b*size[x])%mod)%mod;
 24     add[x]=((add[x]*a)%mod+b)%mod;
 25     mul[x]=(mul[x]*a)%mod;
 26 }
 27 void pushup(UI x){
 28     size[x]=size[c[x][0]]+size[c[x][1]]+1;
 29     sum[x]=(sum[c[x][0]]+sum[c[x][1]]+key[x])%mod;
 30 }
 31 void pushdown(UI x){
 32     UI l=c[x][0],r=c[x][1];
 33     if(rev[x]==true){
 34         rev[x]^=1; rev[l]^=1; rev[r]^=1;
 35         swap(c[x][0],c[x][1]);
 36     }
 37     UI tmpa=add[x],tmpm=mul[x];
 38     add[x]=0; mul[x]=1;
 39     if(tmpa!=0||tmpm!=1){
 40         calc(l,tmpm,tmpa); calc(r,tmpm,tmpa);
 41     }
 42 }
 43 void rotate(UI x){
 44     UI y=fa[x],z=fa[y],l,r;
 45     if(x==c[y][0]) l=0;else l=1; r=l^1;
 46     if(!isroot(y)){
 47         if(y==c[z][0]) c[z][0]=x;
 48         else c[z][1]=x;
 49     }
 50     fa[x]=z; fa[y]=x; fa[c[x][r]]=y;
 51     c[y][l]=c[x][r]; c[x][r]=y;
 52     pushup(y); pushup(x);
 53 }
 54 void splay(UI x){
 55     UI top=0; st[++top]=x;
 56     for(UI i=x;!isroot(i);i=fa[i]){
 57         st[++top]=fa[i];
 58     }
 59     for(UI i=top;i;i--) pushdown(st[i]);
 60     while(!isroot(x)){
 61         UI y=fa[x],z=fa[y];
 62         if(!isroot(y)){
 63             if((x==c[y][0]&&y==c[z][0])||(x==c[y][1]&&y==c[z][1])){
 64                 rotate(y),rotate(x);
 65             }
 66             else rotate(x),rotate(x);
 67         }
 68         else rotate(x);
 69     }
 70 }
 71 void access(UI x){
 72     UI t=0;
 73     while(x){
 74         splay(x);
 75         c[x][1]=t; pushup(x);
 76         t=x; x=fa[x];
 77     }
 78 }
 79 void rever(UI x){
 80     access(x); splay(x); rev[x]^=1;
 81 }
 82 void cut(UI x,UI y){
 83     rever(x); access(y); splay(y); c[y][0]=fa[x]=0;
 84 }
 85 void link(UI x,UI y){
 86     rever(x); fa[x]=y; splay(x);
 87 }
 88 int main(){
 89     scanf("%u%u",&N,&Q);
 90     for(UI i=1;i<=N;i++) key[i]=sum[i]=size[i]=mul[i]=1;
 91     for(UI i=1,u,v;i<=N-1;i++){
 92         scanf("%u%u",&u,&v);
 93         link(u,v);
 94     }
 95     for(UI i=1;i<=Q;i++){
 96         UI u1,v1,u2,v2,cc;
 97         scanf("%s",s);
 98         if(s[0]==‘+‘){
 99             scanf("%u%u%u",&u1,&v1,&cc);
100             rever(u1); access(v1); splay(v1);
101             calc(v1,1,cc);
102         }
103         else if(s[0]==‘-‘){
104             scanf("%u%u%u%u",&u1,&v1,&u2,&v2);
105             cut(u1,v1); link(u2,v2);
106         }
107         else if(s[0]==‘*‘){
108             scanf("%u%u%u",&u1,&v1,&cc);
109             rever(u1); access(v1); splay(v1);
110             calc(v1,cc,0);
111         }
112         else{
113             scanf("%u%u",&u1,&v1);
114             rever(u1); access(v1); splay(v1);
115             printf("%u\n",sum[v1]);
116         }
117     }
118     return 0;
119 }
时间: 2024-11-04 11:40:56

bzoj 2631: tree的相关文章

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的

BZOJ 2631: tree( LCT )

LCT...略麻烦... -------------------------------------------------------------------------------- #include<cstdio> #include<algorithm> #include<cstring> #include<iostream> #define rep( i , n ) for( int i = 0 ; i < n ; ++i ) #define

BZOJ 2631 tree 动态树(Link-Cut-Tree)

题目大意:维护一种树形数据结构.支持下面操作: 1.树上两点之间的点权值+k. 2.删除一条边.添加一条边,保证加边之后还是一棵树. 3.树上两点之间点权值*k. 4.询问树上两点时间点的权值和. 思路:利用动态树维护这棵树,lct的裸题.假设不会下传标记的,先去做BZOJ1798,也是这种标记,仅仅只是在线段树上做,比这个要简单很多. 这个也是我的LCT的第一题,理解起来十分困难啊... CODE: #include <cstdio> #include <cstring> #in

bzoj 2631 LCT

/************************************************************** Problem: 2631 User: wangyucheng Language: C++ Result: Accepted Time:18408 ms Memory:9252 kb ****************************************************************/ #include<iostream> #include

【BZOJ】2631: tree LCT

[题意]给定n个点的树,每个点初始权值为1,m次操作:1.x到y的点加值,2.断一条边并连一条边,保证仍是树,3.x到y的点乘值,4.x到y的点权值和取模.n,m<=10^5. [算法]Link-Cut Tree [题解]区间加和区间乘标记的处理:[BZOJ]1798: [Ahoi2009]Seq 维护序列seq 线段树 splay上维护要注意: 1.上传时加本身. 2.改值的时候不能影响到0点. 3.所有改变点的儿子的地方都要上传,所有改变点的父亲的地方都要下传. 除了rotate,还有acc

BZOJ 3282 Tree Link-Cut-Tree(LCT)

题目大意: 给定N个点以及每个点的权值,要你处理接下来的M个操作.操作有4种.操作从0到3编号.点从1到N编号. 0:后接两个整数(x,y),代表询问从x到y的路径上的点的权值的xor和.保证x到y是联通的. 1:后接两个整数(x,y),代表连接x到y,若x到Y已经联通则无需连接. 2:后接两个整数(x,y),代表删除边(x,y),不保证边(x,y)存在. 3:后接两个整数(x,y),代表将点X上的权值变成Y. 只有会员才知道的世界...有个会员的大神真好 LCT的入门题,切完2631之后这个就

BZOJ 3282: Tree [LCT]

3282: Tree Time Limit: 30 Sec  Memory Limit: 512 MBSubmit: 1677  Solved: 744[Submit][Status][Discuss] Description 给定N个点以及每个点的权值,要你处理接下来的M个操作.操作有4种.操作从0到3编号.点从1到N编号. 0:后接两个整数(x,y),代表询问从x到y的路径上的点的权值的xor和.保证x到y是联通的. 1:后接两个整数(x,y),代表连接x到y,若x到Y已经联通则无需连接.

[bzoj 1468] Tree

传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=1468 Tree Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 1517  Solved: 812[Submit][Status][Discuss] Description 给你一棵TREE,以及这棵树上边的距离.问有多少对点它们两者间的距离小于等于K Input N(n<=40000) 接下来n-1行边描述管道,按照题目中写的输入 接下来是k

BZOJ 3282: Tree

3282: Tree Time Limit: 30 Sec  Memory Limit: 512 MBSubmit: 1714  Solved: 765[Submit][Status][Discuss] Description 给定N个点以及每个点的权值,要你处理接下来的M个操作.操作有4种.操作从0到3编号.点从1到N编号. 0:后接两个整数(x,y),代表询问从x到y的路径上的点的权值的xor和.保证x到y是联通的. 1:后接两个整数(x,y),代表连接x到y,若x到Y已经联通则无需连接.