动态树的基本操作:
1. 添边、删边。
2. 修改一棵树一条链的权值。
3. 给一棵树一条链的权值加上一个数。
4. 查询一棵树一条链上的点,第二大权值、权值第二大点的个数。
1 #include<bits/stdc++.h> 2 #define lc c[x][0] 3 #define rc c[x][1] 4 using namespace std; 5 const int N=1e5+10; 6 const int inf=2e9; 7 int f[N],c[N][2],val[N]; 8 int st[N]; 9 int mx1[N],mx2[N],c1[N],c2[N],siz[N]; 10 int tag_a[N],tag_c[N]; 11 bool rev[N]; 12 13 void init(int n){ 14 for(int i=1;i<=n;i++){ 15 f[i]=c[i][0]=c[i][1]=0; 16 mx1[i]=val[i],mx2[i]=-inf; 17 c1[i]=1,c2[i]=0; 18 siz[i]=1; 19 rev[i]=tag_a[i]=tag_c[i]=0; 20 } 21 } 22 23 inline bool nroot(int x){//判断节点是否为一个Splay的根 24 return c[f[x]][0]==x||c[f[x]][1]==x; 25 } 26 27 void solve(int x,int v,int cnt){ 28 if(v>mx1[x]) mx2[x]=mx1[x],mx1[x]=v,c2[x]=c1[x],c1[x]=cnt; 29 else if(v==mx1[x]) c1[x]+=cnt; 30 else if(v>mx2[x]) mx2[x]=v,c2[x]=cnt; 31 else if(v==mx2[x]) c2[x]+=cnt; 32 } 33 34 void add(int x,int v){ 35 val[x]+=v; mx1[x]+=v; 36 if(mx2[x]!=-inf) mx2[x]+=v; 37 tag_a[x]+=v; 38 } 39 40 void change(int x,int v){ 41 val[x]=mx1[x]=v; 42 mx2[x]=-inf; 43 c1[x]=siz[x],c2[x]=0; 44 tag_c[x]=v; 45 if(tag_a[x]) tag_a[x]=0; 46 } 47 48 void pushup(int x){//上传信息 49 mx1[x]=val[x],mx2[x]=-inf; 50 c1[x]=c2[x]=0; 51 solve(x,val[x],1); 52 if(lc) solve(x,mx1[lc],c1[lc]),solve(x,mx2[lc],c2[lc]); 53 if(rc) solve(x,mx1[rc],c1[rc]),solve(x,mx2[rc],c2[rc]); 54 siz[x]=siz[lc]+siz[rc]+1; 55 } 56 57 inline void pushr(int x){//翻转操作 58 int t=lc; 59 lc=rc,rc=t; 60 rev[x]^=1; 61 } 62 63 void pushdown(int x){//判断并释放懒标记 64 if(rev[x]){ 65 if(lc) pushr(lc); 66 if(rc) pushr(rc); 67 rev[x]=0; 68 } 69 if(tag_c[x]!=-inf){ 70 if(lc) change(lc,tag_c[x]); 71 if(rc) change(rc,tag_c[x]); 72 tag_c[x]=-inf; 73 } 74 if(tag_a[x]){ 75 if(lc) add(lc,tag_a[x]); 76 if(rc) add(rc,tag_a[x]); 77 tag_a[x]=0; 78 } 79 } 80 81 void rotate(int x){//一次旋转 82 int y=f[x],z=f[y],k=c[y][1]==x,w=c[x][!k]; 83 if(nroot(y))c[z][c[z][1]==y]=x;c[x][!k]=y;c[y][k]=w; 84 if(w)f[w]=y;f[y]=x;f[x]=z; 85 pushup(y); 86 } 87 88 void splay(int x){ 89 int y=x,z=0; 90 st[++z]=y; 91 while(nroot(y)) st[++z]=y=f[y]; 92 while(z) pushdown(st[z--]); 93 while(nroot(x)){ 94 y=f[x];z=f[y]; 95 if(nroot(y)) 96 rotate((c[y][0]==x)^(c[z][0]==y)?x:y); 97 rotate(x); 98 } 99 pushup(x); 100 } 101 102 void access(int x){//访问 103 for(int y=0;x;x=f[y=x]) 104 splay(x),rc=y,pushup(x); 105 } 106 107 void makeroot(int x){//换根 108 access(x);splay(x); 109 pushr(x); 110 } 111 112 int findroot(int x){//找根(在真实的树中的) 113 access(x);splay(x); 114 while(lc)pushdown(x),x=lc; 115 splay(x); 116 return x; 117 } 118 119 void split(int x,int y){//提取路径 120 makeroot(x); 121 access(y);splay(y); 122 } 123 124 void link(int x,int y){//连边 125 makeroot(x); 126 if(findroot(y)!=x)f[x]=y; 127 } 128 129 void cut(int x,int y){//断边 130 makeroot(x); 131 if(findroot(y)==x&&f[y]==x&&!c[y][0]){ 132 f[y]=c[x][1]=0; 133 pushup(x); 134 } 135 } 136 137 void query(int x,int y){ 138 split(x,y); 139 if(c1[y]==siz[y]) printf("ALL SAME "); 140 else printf("%d %d ",mx2[y],c2[y]); 141 } 142 143 int main() 144 { 145 int T; 146 scanf("%d",&T); 147 for(int cas=1;cas<=T;cas++){ 148 int n,m; 149 scanf("%d%d",&n,&m); 150 for(int i=1;i<=n;i++){ 151 scanf("%d",&val[i]); 152 } 153 init(n); 154 for(int i=1;i<n;i++){ 155 int u,v; 156 scanf("%d%d",&u,&v); 157 link(u,v); 158 } 159 printf("Case #%d: ",cas); 160 while(m--){ 161 int tp; 162 scanf("%d",&tp); 163 if(tp==1){ 164 int x,y,a,b; 165 scanf("%d%d%d%d",&x,&y,&a,&b); 166 cut(x,y); 167 link(a,b); 168 } 169 else if(tp==2){ 170 int a,b,x; 171 scanf("%d%d%d",&a,&b,&x); 172 split(a,b); 173 change(b,x); 174 } 175 else if(tp==3){ 176 int a,b,d; 177 scanf("%d%d%d",&a,&b,&d); 178 split(a,b); 179 add(b,d); 180 } 181 else{ 182 int a,b; 183 scanf("%d%d",&a,&b); 184 query(a,b); 185 } 186 } 187 } 188 return 0; 189 }