hahahaha!
今天(3月12)我终于ac了……
orz Yan Big God!
他问我能不能
O(n)
建树……
并且提供了一个“反映射“的思想。
我想我们连反映射都可以不要……
鉴于ZKW的特殊性……
我们只要
for(int i=1;i<n;++i){
if(dep[d[i][0]]<dep[d[i][1]]) swap(d[i][0],d[i][1]);
t[w[d[i][0]]+M]=d[i][2];
}//w是树上节点到线段树的映射,M是ZKW线段树的偏移量
for(int i=M-1;i;--i) t[i]=max(t[i<<1],t[i<<1|1]);
这样可以使
O(nlogn)
的建树复杂度降至
O(n)
.
【这道题貌似用LCT也能A,不过splay常数大的要死(0.63,树剖0.23)- -我还以为我要T了呢- -】
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int maxn=30001;
typedef int arr[maxn<<1];
typedef int arr1[maxn];
int M,t[65536];
arr next,to;
arr1 list,fa,dep,size,son,top,w;
int rt,n,tot,ttot,z,d[maxn][3];
inline void add(int a,int b){
++tot;
next[tot]=list[a];
list[a]=tot;
to[tot]=b;
++tot;
next[tot]=list[b];
list[b]=tot;
to[tot]=a;
}
bool visit[20000];
void dfs(int v){
size[v]=1;son[v]=0;
for(int k=list[v];k;k=next[k])
if(to[k]!=fa[v]){
fa[to[k]]=v;
dep[to[k]]=dep[v]+1;
dfs(to[k]);
size[v]+=size[to[k]];
if(size[to[k]]>size[son[v]])
son[v]=to[k];
}
}
void buildtree(int v,int tp){
w[v]=++z;top[v]=tp;
if(son[v]) buildtree(son[v],top[v]);
for(int k=list[v];k;k=next[k])
if(to[k]!=fa[v]&&to[k]!=son[v])
buildtree(to[k],to[k]);
}
inline void change(int p,int x){
for(t[p+=M]=x,p>>=1;p;p>>=1) t[p]=max(t[p<<1],t[p<<1|1]);
}
int query(int L,int R){
int ans=1<<31;
for(L+=M-1,R+=M+1;L^R^1;L>>=1,R>>=1){
if(~L&1) ans=max(ans,t[L^1]);
if( R&1) ans=max(ans,t[R^1]);
}
return ans;
}
inline int find(int va,int vb){
int f1=top[va],f2=top[vb],tmp=1<<31;
while(f1!=f2){
if(dep[f1]<dep[f2])
swap(f1,f2),swap(va,vb);
tmp=max(tmp,query(w[f1],w[va]));
va=fa[f1];f1=top[va];
}
if(va==vb)return tmp;
if(dep[va]>dep[vb]) swap(va,vb);
return max(tmp,query(w[son[va]],w[vb]));
}
inline int read(){
int x=0;
char ch=getchar();
while(!isdigit(ch)){ch=getchar();}
while(isdigit(ch)){x=x*10+ch-48;ch=getchar();}
return x;
}
inline void init(){
n=read();
M=1;
while(M<=n) M<<=1;
memset(list,0,sizeof(int)*(n+1));
ttot=rt=z=0;
tot=0;
for(int i=1;i<n;++i){
d[i][0]=read(),d[i][1]=read(),d[i][2]=read();
add(d[i][0],d[i][1]);
}
dfs(1);
buildtree(1,1);
for(int i=1;i<n;++i){
if(dep[d[i][0]]<dep[d[i][1]]) swap(d[i][0],d[i][1]);
t[w[d[i][0]]+M]=d[i][2];
}
for(int i=M-1;i;--i) t[i]=max(t[i<<1],t[i<<1|1]);
}
int a[10];
inline void print(int x){
if(x) a[0]=0;
else a[1]=0,a[0]=1;
while(x) a[++a[0]]=x%10,x/=10;
for(;a[0];--a[0])
putchar(a[a[0]]+48);
putchar('\n');
}
int main(){
char ch;
int x,y,t;
for(t=read();t;--t){
init();
while(1){
ch=getchar();
while(ch!='D'&&ch!='Q'&&ch!='C') ch=getchar();
if(ch=='D') break;
if(ch=='Q')
print(find(read(),read()));
else{
x=read(),y=read();
change(w[d[x][0]],y);
}
}
putchar('\n');
}
return 0;
}
这是LCT版的:(我旋转居然又写挂了- -)因为要把一条边也当做点来处理所以数组开大点- -
#include<cstdio>
#include<cstring>
#include<iostream>
#define STOP do{puts("there");while(1);}while(0)
using namespace std;
const int maxn=90001;
const int inf=1<<30;
struct node{
node *f,*ch[2];
int v,s,maxi;bool p,flip;
inline bool isRoot();
inline void rev(){flip^=1;}
inline void upd(){
s=ch[0]->s+ch[1]->s+1;
maxi=max(v,max(ch[0]->maxi,ch[1]->maxi));
}
}t[maxn],*stack[maxn],*cur=t;
int n;
inline bool node::isRoot(){return f==t||this!=f->ch[p];}
inline node *NewNode(node *f=t,int v=-inf){
++cur;
cur->f=f;
cur->ch[0]=cur->ch[1]=t;
cur->s=1;
cur->v=v;
cur->flip=false;
cur->maxi=v;
return cur;
}
inline void sc(node *a,node *b,bool c){
a->ch[c]=b;b->f=a;b->p=c;
}
inline void pushdown(node *x){
if(x->flip){//其实if(x->ch[0]!=t)不必判断的
if(x->ch[0]!=t) x->ch[0]->p^=1,x->ch[0]->flip^=1;
if(x->ch[1]!=t) x->ch[1]->p^=1,x->ch[1]->flip^=1;
swap(x->ch[0],x->ch[1]);
x->flip=0;//!!!!!!!!!
}
}
inline void rot(node *x){
node *y=x->f;bool p=x->p;
if(y->isRoot()) x->f=y->f;
else sc(y->f,x,y->p);
sc(y,x->ch[!p],p);
sc(x,y,!p);
y->upd();
}
inline void splay(node *x){
int top;stack[top=1]=x;
for(node *p=x;!p->isRoot();p=p->f) stack[++top]=p->f;
while(top) pushdown(stack[top--]);
while(!x->isRoot()){
if(x->f->isRoot()) rot(x);
else if(x->f->p==x->p) rot(x->f),rot(x);
else rot(x),rot(x);
// cout<<"锕";
}//cout<<"铪\n";
x->upd();
}
inline void splice(node *x){splay(x->f);sc(x->f,x,1);x->f->upd();splay(x);}
inline void expose(node *x){splay(x);while(x->f!=t) splice(x);}
inline void reroot(node *x){expose(x);x->ch[1]=t;x->upd();x->rev();}
inline void link(node *x,node *y){
expose(x);
x->ch[0]=y;x->upd();
}
inline int query(node *x,node *y){
reroot(x);reroot(y);
return y->maxi;
}
inline void change(node *x,int toWhat){
splay(x);
x->v=toWhat;
x->upd();
}
inline int read(){
int x=0;
char ch=getchar();
while(!isdigit(ch)) ch=getchar();
while(isdigit(ch)) x=x*10+ch-48,ch=getchar();
return x;
}
node *idx[maxn<<1];
int tot,to[maxn<<1],next[maxn<<1],list[maxn],cost[maxn<<1];
inline void add(int a,int b,int c){
next[++tot]=list[a];
list[a]=tot;
to[tot]=b;
cost[tot]=c;
}
int q[maxn];
node *fa[maxn];
inline void bfs(){
int head=0,tail=1,h;
q[1]=1;
fa[1]=t;
while(head<tail){
h=q[++head];
idx[h]=NewNode(fa[h]?fa[h]:t);
for(int k=list[h];k;k=next[k])
if(!idx[to[k]]){
idx[(k+1>>1)+n]=NewNode(idx[h],cost[k]);
fa[to[k]]=idx[(k+1>>1)+n];
q[++tail]=to[k];
}
}
}
inline void dfs(int x,node *f=t){
idx[x]=NewNode(f);
}
#define CLR(x) memset(x,0,sizeof x)
inline void init(){
memset(idx,0,sizeof(node*)*(cur-t+1));
memset(list,0,sizeof(int)*(n+1));
tot=0;
cur=t;
t[0].maxi=1<<31;
t[0].f=t;
t[0].ch[0]=t[0].ch[1]=t;
}
int main(){
int T=read(),a,b,c;
char cmd[10];
while(T--){
init();
n=read();
for(int i=1;i<n;++i){
a=read(),b=read();c=read();
add(a,b,c);add(b,a,c);
}
bfs();
for(;;){
scanf("%s",cmd);
if(cmd[0]=='D') break;
else if(cmd[0]=='Q'){
a=read();b=read();
printf("%d\n",query(idx[a],idx[b]));
}
else{
a=read();b=read();
change(idx[a+n],b);
}
}
putchar('\n');
}
}