wjyi

人这么弱,有什么资格颓废(ಥ _ ಥ)

  博客园  :: 首页  :: 新随笔  :: 联系 ::  :: 管理

2016-06-01 08:50:36

题目:http://www.lydsy.com/JudgeOnline/problem.php?id=2631

注意加和乘的标记下传问题。

还有就是split后,要分清x和y哪个是祖先。

pushup在access和rotate后都要进行。

这题还卡常数,开ll就会T,开unsigned int即可。

  1 #include<bits/stdc++.h>
  2 #define inf 1000000000
  3 #define uint unsigned int
  4 #define N 100005
  5 #define mod 51061
  6 using namespace std;
  7 int read(){
  8   int x=0,f=1;char ch=getchar();
  9   while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
 10   while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
 11   return x*f;
 12 }
 13 int n,q;
 14 char ch[5];
 15 namespace LCT{
 16   int ch[N][2],fa[N],sz[N];bool rev[N];
 17   uint cj[N],add[N],val[N],sum[N];
 18   inline bool isroot(int x){
 19     if(ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x)return 1;return 0;
 20   }
 21   void change(int x,int c,int a){
 22     if(!x)return;
 23     val[x]=(val[x]*c+a)%mod;
 24     sum[x]=(sum[x]*c+a*sz[x])%mod;
 25     add[x]=(add[x]*c+a)%mod;
 26     cj[x]=(cj[x]*c)%mod;
 27   }
 28   void pushdown(int x){
 29     if(rev[x]){
 30       rev[ch[x][0]]^=1;rev[ch[x][1]]^=1;rev[x]^=1;
 31       swap(ch[x][0],ch[x][1]);
 32     }
 33     if(cj[x]!=1||add[x]!=0){
 34       change(ch[x][0],cj[x],add[x]);
 35       change(ch[x][1],cj[x],add[x]);
 36     }
 37     cj[x]=1;add[x]=0;
 38   }
 39   void Pushdown(int x){
 40     if(!isroot(x))Pushdown(fa[x]);
 41     pushdown(x);
 42   }
 43   void pushup(int x){
 44     sum[x]=(sum[ch[x][0]]+sum[ch[x][1]]+val[x])%mod;
 45     sz[x]=(sz[ch[x][0]]+sz[ch[x][1]]+1)%mod;
 46   }
 47   void rotate(int x){
 48     int y=fa[x],k=ch[y][1]==x;
 49     if(!isroot(y))ch[fa[y]][ch[fa[y]][1]==y]=x;
 50     fa[x]=fa[y];
 51     fa[ch[x][!k]]=y;
 52     fa[y]=x;
 53     ch[y][k]=ch[x][!k];
 54     ch[x][!k]=y;
 55     pushup(y);pushup(x);
 56   }
 57   void splay(int x){
 58     Pushdown(x);
 59     for(int y=fa[x];!isroot(x);y=fa[x]){
 60       if(!isroot(y)){
 61         if((ch[fa[y]][ch[fa[y]][1]==y])!=(ch[y][1]==x))rotate(x);
 62         else rotate(y);
 63       }rotate(x);
 64     }
 65   }
 66   inline void access(int x){
 67     int y=0;
 68     while(x){
 69       splay(x);
 70       ch[x][1]=y;pushup(x);
 71       x=fa[y=x];
 72     }
 73   }
 74   inline void moveroot(int x){
 75     access(x);splay(x);rev[x]^=1;
 76   }
 77   inline void link(int x,int y){
 78     moveroot(x);fa[x]=y;splay(x);
 79   }
 80   inline void cut(int x,int y){
 81     moveroot(x);access(y);splay(y);ch[y][0]=fa[x]=0;
 82   }
 83   inline void split(int x,int y){
 84     moveroot(y);access(x);splay(x);
 85   }
 86 }
 87 int main(){
 88   n=read();q=read();
 89   for(int i=1;i<=n;i++)LCT::val[i]=LCT::sum[i]=LCT::cj[i]=LCT::sz[i]=1;
 90   for(int i=1;i<n;i++)LCT::link(read(),read());
 91   while(q--){
 92     scanf("%s",ch);
 93     int u=read(),v=read();
 94     if(ch[0]=='+')LCT::split(u,v),LCT::change(u,1,read());
 95     else if(ch[0]=='-'){
 96       LCT::cut(u,v);u=read();v=read();LCT::link(u,v);
 97     }
 98     else if(ch[0]=='*')LCT::split(u,v),LCT::change(u,read(),0);
 99     else LCT::split(u,v),printf("%d\n",LCT::sum[u]%mod);
100   }
101   return 0;
102 }
View Code

2631: tree

Time Limit: 30 Sec  Memory Limit: 128 MB
Submit: 3385  Solved: 1137
[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

 

posted on 2016-06-01 08:59  wjyi  阅读(173)  评论(0编辑  收藏  举报