您的位置:首页 > 其它

【BZOJ3531】旅行(线段树)

2017-07-20 10:31 495 查看
传送门

I Think

题意:一棵树上节点有两个点权c1,c2,求(x,y)两点路径中c2与x的c2相同的城市的c1总和/最大值,两个点权均带修改。

算法:线段树(动态开点)+树链剖分

实现:对每一种c2(信仰)建立线段树,维护以之为信仰的城市的c1。

Attention!

1)动态删点要带&

2)对于每一个修改操作,不仅在线段树上更改,还要更改原数组的值。

Code

#include<cstdio>
using namespace std;

const int sm = 1e5+2;
const int sn = sm<<6;

template <typename T> void read(T &x) {
char ch=getchar();x=0;
while(ch>'9'||ch<'0') ch=getchar();
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
}
char Hint[3];
int N,Q,tot,t;
int sum[sn],mx[sn],c[sm],w[sm],T[sm],stk[sm];
int hd[sm],to[sm<<1],nxt[sm<<1],Ls[sn],Rs[sn];
int Fa[sm][18],dep[sm],son[sm],sz[sm],top[sm],pl[sm];

void Swap(int &x,int &y) { int t=x;x=y;y=t; }
int Max(int x,int y) { return x>y?x:y; }
void Add(i
4000
nt u,int v) {
to[++tot]=v,nxt[tot]=hd[u],hd[u]=tot;
to[++tot]=u,nxt[tot]=hd[v],hd[v]=tot;
}
void Dfsa(int x,int fa) {
Fa[x][0]=fa,dep[x]=dep[fa]+1,sz[x]=1;
for(int i=1;i<=17;++i)
if(Fa[x][i-1])Fa[x][i]=Fa[Fa[x][i-1]][i-1];
else break;
for(int i=hd[x];i;i=nxt[i])
if(to[i]!=fa) {
Dfsa(to[i],x),sz[x]+=sz[to[i]];
if(sz[son[x]]<sz[to[i]])son[x]=to[i];
}
}
void Dfsb(int x,int tp) {
pl[x]=++tot,top[x]=tp;
if(son[x]) Dfsb(son[x],top[x]);
for(int i=hd[x];i;i=nxt[i])
if(to[i]!=Fa[x][0]&&to[i]!=son[x])
Dfsb(to[i],to[i]);
}
void Up(int rt) {
mx[rt]=Max(mx[Ls[rt]],mx[Rs[rt]]);
sum[rt]=sum[Ls[rt]]+sum[Rs[rt]];
}
void del(int &rt) {
stk[++t]=rt,mx[rt]=sum[rt]=0,rt=0;
}
void Modify(int &rt,int l,int r,int p,int val) {
if(!rt) { if(t) rt=stk[t--]; else rt=++tot;}
if(l==r) { mx[rt]=sum[rt]=val; if(!mx[rt])del(rt); return; }
int m=(l+r)>>1;
if(p<=m) Modify(Ls[rt],l,m,p,val);
else Modify(Rs[rt],m+1,r,p,val);
if(!Ls[rt]&&!Rs[rt]) del(rt);
else Up(rt);
}
int Maxn(int rt,int l,int r,int a,int b) {
if(!rt||l>b||r<a) return 0;
if(a<=l&&r<=b) return mx[rt];
int m=(l+r)>>1,ans=0;
if(a<=m) ans=Max(ans,Maxn(Ls[rt],l,m,a,b));
if(b> m) ans=Max(ans,Maxn(Rs[rt],m+1,r,a,b));
return ans;
}
int Sum(int rt,int l,int r,int a,int b) {
if(!rt)return 0;
if(a<=l&&r<=b) return sum[rt];
int m=(l+r)>>1,ans=0;
if(a<=m) ans+=Sum(Ls[rt],l,m,a,b);
if(b> m) ans+=Sum(Rs[rt],m+1,r,a,b);
return ans;
}
int Q_max(int a,int b) {
int og=T[c[a]],tmp=0;
while(top[a]!=top[b]) {
if(dep[top[a]]<dep[top[b]])Swap(a,b);
tmp=Max(tmp,Maxn(og,1,N,pl[top[a]],pl[a]));
a=Fa[top[a]][0];
}
if(pl[a]>pl[b]) Swap(a,b);
tmp=Max(tmp,Maxn(og,1,N,pl[a],pl[b]));
return tmp;
}
int Q_sum(int a,int b) {
int og=T[c[a]],ret=0;
while(top[a]!=top[b]) {
if(dep[top[a]]<dep[top[b]]) Swap(a,b);
ret+=Sum(og,1,N,pl[top[a]],pl[a]);
a=Fa[top[a]][0];
}
if(pl[a]>pl[b])Swap(a,b);
ret+=Sum(og,1,N,pl[a],pl[b]);
return ret;
}
int Lca(int u,int v) {
if(dep[u]!=dep[v]) {
if(dep[u]<dep[v]) Swap(u,v);
for(int i=17;i>=0;--i)
if(dep[Fa[u][i]]>dep[v])
u=Fa[u][i];
u=Fa[u][0];
}
if(u==v) return v;
for(int i=17;i>=0;--i)
if(Fa[u][i]!=Fa[v][i])
u=Fa[u][i],v=Fa[v][i];
return Fa[u][0];
}
int main() {
read(N),read(Q);
for(int i=1;i<=N;++i)
read(w[i]),read(c[i]);
for(int i=1,a,b;i<N;++i)
read(a),read(b),Add(a,b);
tot=0,Dfsa(1,0),Dfsb(1,1),tot=0;
for(int i=1;i<=N;++i)
Modify(T[c[i]],1,N,pl[i],w[i]);
for(int i=1,x,y,lc,S;i<=Q;++i) {
scanf("%s",Hint);
read(x),read(y);
if(Hint[0]=='C') {
if(Hint[1]=='C') {
Modify(T[c[x]],1,N,pl[x],0),c[x]=y;
Modify(T[c[x]],1,N,pl[x],w[x]);
}
else Modify(T[c[x]],1,N,pl[x],y),w[x]=y;//别忘记更新
}
else{
lc=Lca(x,y);
if(Hint[1]=='S')
printf("%d\n",Q_sum(x,lc)+Q_sum(y,lc)-(c[lc]==c[x])*w[lc]);
else
printf("%d\n",Max(Q_max(x,lc),Q_max(y,lc)));
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: