题目传送门:http://acm.hdu.edu.cn/showproblem.php?pid=5002
题目大意:一开始给你一棵有N个点的树(N<=10^5),每个点有权值。现在有四种操作:1:x y a b删掉连接x,y的边,并连接a,b,保证操作完后还是一棵树;2:a b x 将a到b路径上的点权值全部变为x;3:a b d 将a到b路径上的点权值全部+d;4:a b 询问a到b中路径上第二大的数是多少(注意,是严格的第二大),以及有多少个。如果没有第二大的数,输出“ALL SAME”。操作个数M<=10^5,一个测试点有不超过3组数据。
题目分析:编程一中午,码出动态树。——第一道LCT
这题算是LCT的半裸题吧。前面的操作都很简单,但是我们如何知道一条链上第二大的数有几个呢?我想先求出第二大的数是几,然后搞一棵可持久化线段树之类乱七八糟脑洞大开地维护每一个数在每一条链上出现几次,然后死命想不出来。直到tututu一语惊醒梦中人:在splay的节点处维护一个最大值,以及最大的个数,还有次大值和次大值的个数不就好了吗?合并的时候讨论一下。我这才发现我好像做数据结构题已经做傻了,把问题复杂化QAQ……
然后码了一个中午,最后发现WA的原因竟然是忘了开long long……
CODE:
#include<iostream>
#include<string>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<stdio.h>
#include<algorithm>
using namespace std;const int maxn=100100;
const long long oo=11000000000000001LL;
const long long low=-11000000000001LL;
typedef long long LL;struct Tnode;
void Update(Tnode *,Tnode *);
void Add(LL ,Tnode *);
void Change(LL ,Tnode *);struct Tnode
{LL val,max1,max2,change,add;int Size,num1,num2,path_parent;bool flip;Tnode *fa,*son[2];int Get_d() { return fa->son[1]==this; }void Connect(Tnode *P,int d) { (son[d]=P)->fa=this; }void Up(){Size=(son[0]? son[0]->Size:0)+(son[1]? son[1]->Size:0)+1;max1=val,num1=1;max2=-oo,num2=0;if (son[0]) Update(this,son[0]);if (son[1]) Update(this,son[1]);}void Push_down(){if (flip){swap(son[0],son[1]);if (son[0]) son[0]->flip^=1;if (son[1]) son[1]->flip^=1;flip=false;}if (add){if (son[0]) Add(add,son[0]);if (son[1]) Add(add,son[1]);add=0;}if (change<oo){if (son[0]) Change(change,son[0]);if (son[1]) Change(change,son[1]);change=oo;}}
} tree[maxn];void Work(Tnode *x,LL Max,int Num)
{if (Max>x->max1) x->max2=x->max1,x->num2=x->num1,x->max1=Max,x->num1=Num;elseif (Max==x->max1) x->num1+=Num;elseif (Max>x->max2) x->max2=Max,x->num2=Num;else if (Max==x->max2) x->num2+=Num;
}void Update(Tnode *x,Tnode *y)
{Work(x,y->max1,y->num1);Work(x,y->max2,y->num2);
}void Add(LL a,Tnode *y)
{if (y->change<oo) y->change+=a;else y->add+=a;y->val+=a;y->max1+=a;y->max2+=a;
}void Change(LL c,Tnode *y)
{y->val=y->max1=y->change=c;y->add=0LL;y->num1=y->Size;y->max2=-oo;y->num2=0;
}Tnode *Node[maxn];
int cur;int t,n,m;Tnode *New_node(LL v)
{cur++;tree[cur].val=tree[cur].max1=v;tree[cur].Size=tree[cur].num1=1;tree[cur].max2=-oo;tree[cur].num2=0;tree[cur].change=oo;tree[cur].add=tree[cur].path_parent=0;tree[cur].flip=false;tree[cur].fa=tree[cur].son[0]=tree[cur].son[1]=NULL;return tree+cur;
}void Push(Tnode *P)
{if (!P) return;Push(P->fa);P->Push_down();
}void Zig(Tnode *P)
{int d=P->Get_d();Tnode *F=P->fa;if (P->son[!d]) F->Connect(P->son[!d],d);else F->son[d]=NULL;if (F->fa) F->fa->Connect(P,F->Get_d());else P->fa=NULL;F->Up();P->Connect(F,!d);P->path_parent=F->path_parent;F->path_parent=0;
}void Splay(Tnode *P)
{Push(P);while (P->fa){Tnode *F=P->fa;if (F->fa) ( F->Get_d()^P->Get_d() )? Zig(P):Zig(F);Zig(P);}P->Up();
}void Down(int x)
{Splay(Node[x]);if (Node[x]->son[1]) Node[x]->son[1]->fa=NULL,Node[x]->son[1]->path_parent=x;Node[x]->son[1]=NULL;Node[x]->Up();
}void Access(int x)
{Down(x);int y=Node[x]->path_parent;while (y){Down(y);Node[y]->Connect(Node[x],1);Node[y]->Up();Node[x]->path_parent=0;x=y;y=Node[x]->path_parent;}
}void Evert(int x)
{Access(x);Splay(Node[x]);Node[x]->flip^=1;
}void Link(int x,int y)
{Evert(y);Splay(Node[y]);Node[y]->path_parent=x;
}void Cut(int x,int y)
{Evert(x);Access(y);Splay(Node[x]);Node[x]->son[1]->fa=NULL,Node[x]->son[1]->path_parent=0;Node[x]->son[1]=NULL;Node[x]->Up();
}int main()
{freopen("c.in","r",stdin);freopen("c.out","w",stdout);scanf("%d",&t);for (int g=1; g<=t; g++){printf("Case #%d:\n",g);scanf("%d%d",&n,&m);cur=-1;for (int i=1; i<=n; i++){int v;scanf("%d",&v);Node[i]=New_node(v);}for (int i=1; i<n; i++){int u,v;scanf("%d%d",&u,&v);Link(u,v);}for (int i=1; i<=m; i++){int c;scanf("%d",&c);if (c==1){int x,y,a,b;scanf("%d%d%d%d",&x,&y,&a,&b);Cut(x,y);Link(a,b);}if (c==2){int a,b,x;scanf("%d%d%d",&a,&b,&x);Evert(a);Access(b);Splay(Node[a]);Change(x,Node[a]);}if (c==3){int a,b,d;scanf("%d%d%d",&a,&b,&d);Evert(a);Access(b);Splay(Node[a]);Add(d,Node[a]);}if (c==4){int a,b;scanf("%d%d",&a,&b);Evert(a);Access(b);Splay(Node[a]);if (Node[a]->max2<=low) printf("ALL SAME\n");else printf("%I64d %d\n",Node[a]->max2,Node[a]->num2);}}}return 0;
}