P3313 [SDOI2014] 旅行

P3313 [SDOI2014] 旅行

题意简述:

给一颗树,点有点权以及颜色,要求实现四种操作:

1.修改某点点权
2.修改某点颜色
3.求一条树上最短路(x,y)上颜色与 x,y 都相同的点的点权和,保证 x,y颜色相同
4.求一条树上最短路(x,y)上颜色与 x,y 都相同的点的点权最大值,保证 x,y颜色相同

1n,m,C105

C 表示颜色种数

Solution:

有些猎奇的树链剖分和动态开点线段树。

我们看完题目不难想到树链剖分,但是我们会发现颜色这一限制有些棘手,我们不妨转换一下,我们用树链剖分的思想得到一些连续的树链对应连续的下标区间。

然后我们维护一个动态开点线段树,其下标是又两个数字拼成的一个数: pos=colC+id 这样一来,对于一个查询,我们设 k=colx

对于一个连续的树上下标区间,我们在线段树上查询区间 [kC+l,kC+r] 就能得到答案了

Code:

#include<bits/stdc++.h>
#define int long long
const int N=1e5+5;
const int inf=N*N;
using namespace std;
int n,m,rt;
int col[N],w[N];
char c[N];
inline int Max(int x,int y)
{
return x > y ? x : y;
}
//Segment_Tree
struct Segment_Tree{
int cnt;
struct Tree{
int ls,rs,cnt,sum,mx;
}t[N*40];
void pushup(int x)
{
t[x].sum=t[t[x].ls].sum+t[t[x].rs].sum;
t[x].mx = t[t[x].ls].mx > t[t[x].rs].mx ? t[t[x].ls].mx : t[t[x].rs].mx;
}
void insert(int &x,int l,int r,int pos,int val)
{
if(!x)x=++cnt;
if(l==r){t[x].sum+=val;t[x].mx=t[x].sum;return;}
int mid=l+r>>1;
if(pos<=mid)insert(t[x].ls,l,mid,pos,val);
if(mid<pos) insert(t[x].rs,mid+1,r,pos,val);
pushup(x);
}
int query(int x,int l,int r,int L,int R)
{
if(L<=l&&r<=R)return t[x].sum;
int mid=l+r>>1,res=0;
if(L<=mid)res+=query(t[x].ls,l,mid,L,R);
if(mid<R)res+=query(t[x].rs,mid+1,r,L,R);
return res;
}
int ask(int x,int l,int r,int L,int R)
{
if(L<=l&&r<=R)return t[x].mx;
int mid=l+r>>1,res=0;
if(L<=mid) res = Max(res,ask(t[x].ls,l,mid,L,R));
if(mid<R) res = Max(res,ask(t[x].rs,mid+1,r,L,R));
return res;
}
}T;
struct Graph{
int head[N];
struct Edge{
int to,nxt;
}e[N<<1];
void add(int x,int y)
{
e[++head[0]]=Edge{y,head[x]};
head[x]=head[0];
}
int fa[N],dep[N],dfn[N],rid[N];
int siz[N],son[N],top[N];
void dfs1(int x,int ff)
{
dep[x]=dep[fa[x]=ff]+1;
for(int i=head[x];i;i=e[i].nxt)
{
int y=e[i].to;
if(y==fa[x])continue;
dfs1(y,x);
siz[x] += siz[y];
son[x] = siz[son[x]] > siz[y] ? son[x] : y;
}
}
void dfs2(int x,int tp)
{
dfn[x]=++dfn[0];rid[dfn[0]]=x;
top[x]=tp;
if(!son[x])return;
dfs2(son[x],tp);
for(int i=head[x];i;i=e[i].nxt)
{
int y=e[i].to;
if(y==fa[x]||y==son[x])continue;
dfs2(y,y);
}
}
int chain_query(int x,int y,int k)
{
int res=0;
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]])swap(x,y);
res+=T.query(rt,1,inf,k*N+dfn[top[x]],k*N+dfn[x]);
x=fa[top[x]];
}
if(dep[x]<dep[y])swap(x,y);
res+=T.query(rt,1,inf,k*N+dfn[y],k*N+dfn[x]);
return res;
}
int chain_ask(int x,int y,int k)
{
int res=0;
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]])swap(x,y);
res=Max(res,T.ask(rt,1,inf,k*N+dfn[top[x]],k*N+dfn[x]));
x=fa[top[x]];
}
if(dep[x]<dep[y])swap(x,y);
res=Max(res,T.ask(rt,1,inf,k*N+dfn[y],k*N+dfn[x]));
return res;
}
}G;
void work()
{
cin>>n>>m;
for(int i=1;i<=n;i++)scanf("%lld%lld",&w[i],&col[i]);
for(int i=1,x,y;i<n;i++)
{
scanf("%lld%lld",&x,&y);
G.add(x,y);G.add(y,x);
}
G.dfs1(1,0);
G.dfs2(1,1);
for(int i=1;i<=n;i++)
{
int x=G.rid[i];
T.insert(rt,1,inf,col[x]*N+i,w[x]);
}
for(int i=1,x,y;i<=m;i++)
{
scanf("%s",c);
scanf("%lld%lld",&x,&y);
if(c[1]=='C')
{
int u=G.dfn[x];
T.insert(rt,1,inf,col[x]*N+u,-w[x]);
col[x]=y;
T.insert(rt,1,inf,col[x]*N+u,w[x]);
}
if(c[1]=='W')
{
int u=G.dfn[x];
T.insert(rt,1,inf,col[x]*N+u,y-w[x]);
w[x]=y;
}
if(c[1]=='S')
{
int ans=G.chain_query(x,y,col[x]);
printf("%lld\n",ans);
}
if(c[1]=='M')
{
int ans=G.chain_ask(x,y,col[x]);
printf("%lld\n",ans);
}
}
}
#undef int
int main()
{
//freopen("P3313_2.in","r",stdin);freopen("P3313.out","w",stdout);
work();
return 0;
}
posted @   liuboom  阅读(6)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
点击右上角即可分享
微信分享提示