题目:
题解:
第一次(?)超200行鼓掌
树链剖分模板题------维护边权,解决方法:把边权放到较深的点中去,这样root就不能进行计算,查询的时候只要找到根的重儿子就行(想想看?)(因为f1!=f2的时候一个点一定在根节点上,另一个点肯定是重链上的点)
第二个不一样的问题就是取反,设置delta数组进行取反,别忘了change值得时候delta变成0
代码:
#include <cstdio>
#include <cstring>
#include <iostream>
#define MIN -1e9
#define MAX 1e9
#define N 20005
using namespace std;
struct hh
{
int a,b,z;
}w[20005];
int size[N*4],ww[N*4],son[N*4],fa[N*4],deep[N*2+5],delta[N*4+5];
int top[N*4],num[N*4],tree[N*4],totw=0;
int sum[N*4],maxn[N*4],minn[N*4];
int next[N*2+5],point[N*2+5],v[N*2+5],tot=0;
int n,i,a,b,x,m;
void addline(int x,int y)
{
++tot; next[tot]=point[x]; point[x]=tot; v[tot]=y;
++tot; next[tot]=point[y]; point[y]=tot; v[tot]=x;
}
void updata(int now)
{
if (now)
{
maxn[now]=max(maxn[now<<1],maxn[now<<1|1]);
sum[now]=sum[now<<1]+sum[now<<1|1];
minn[now]=min(minn[now<<1],minn[now<<1|1]);
}
}
void pushdown(int now)
{
if (delta[now])
{
delta[now<<1]^=1;
delta[now<<1|1]^=1;
int xhh=maxn[now<<1];
maxn[now<<1]=-minn[now<<1];
minn[now<<1]=-xhh;
sum[now<<1]=-sum[now<<1];
xhh=maxn[now<<1|1];
maxn[now<<1|1]=-minn[now<<1|1];
minn[now<<1|1]=-xhh;
sum[now<<1|1]=-sum[now<<1|1];
delta[now]=0;
}
}
void dfs_1(int now,int dep,int faa)
{
deep[now]=dep;
fa[now]=faa;
size[now]=1;
int maxx=0;
for (int i=point[now];i;i=next[i])
if (v[i]!=faa)
{
dfs_1(v[i],dep+1,now);
size[now]+=size[v[i]];
if (size[v[i]]>maxx)
{
maxx=size[v[i]];
son[now]=v[i];
}
}
}
void dfs_2(int now,int faa)
{
if (son[faa]!=now) top[now]=now;
else top[now]=top[faa];
num[now]=++totw;
if (son[now])
{
dfs_2(son[now],now);
for (int i=point[now];i;i=next[i])
if (v[i]!=son[now] && v[i]!=faa)
dfs_2(v[i],now);
}
}
void build(int now,int l,int r)
{
if (l==r)
{
maxn[now]=ww[tree[l]];
minn[now]=ww[tree[l]];
sum[now]=ww[tree[l]];
return;
}
int mid=(l+r)>>1;
build(now<<1,l,mid);
build(now<<1|1,mid+1,r);
updata(now);
}
void change(int now,int l,int r,int x,int v)
{
if (l==r)
{
delta[now]=0;
maxn[now]=v;
minn[now]=v;
sum[now]=v;
return;
}
pushdown(now);
int mid=(l+r)>>1;
if (x<=mid) change(now<<1,l,mid,x,v);
else change(now<<1|1,mid+1,r,x,v);
updata(now);
}
void qf(int now,int l,int r,int lrange,int rrange)
{
if (lrange<=l && rrange>=r)
{
delta[now]^=1;
int xhh=maxn[now];
maxn[now]=-minn[now];
minn[now]=-xhh;
sum[now]=-sum[now];
return;
}
pushdown(now);
int mid=(l+r)>>1;
if (mid>=lrange)
qf(now<<1,l,mid,lrange,rrange);
if (mid<rrange)
qf(now<<1|1,mid+1,r,lrange,rrange);
updata(now);
}
int qmax(int now,int l,int r,int lrange,int rrange)
{
if (lrange<=l && rrange>=r) return maxn[now];
pushdown(now);
int mid=(l+r)>>1;
int ans=MIN;
if (mid>=lrange)
ans=max(ans,qmax(now<<1,l,mid,lrange,rrange));
if (mid<rrange)
ans=max(ans,qmax(now<<1|1,mid+1,r,lrange,rrange));
return ans;
}
int qmin(int now,int l,int r,int lrange,int rrange)
{
if (lrange<=l && rrange>=r) return minn[now];
pushdown(now);
int mid=(l+r)>>1;
int ans=MAX;
if (mid>=lrange)
ans=min(ans,qmin(now<<1,l,mid,lrange,rrange));
if (mid<rrange)
ans=min(ans,qmin(now<<1|1,mid+1,r,lrange,rrange));
return ans;
}
int qsum(int now,int l,int r,int lrange,int rrange)
{
if (lrange<=l && rrange>=r) return sum[now];
pushdown(now);
int mid=(l+r)>>1;
int ans=0;
if (mid>=lrange)
ans+=qsum(now<<1,l,mid,lrange,rrange);
if (mid<rrange)
ans+=qsum(now<<1|1,mid+1,r,lrange,rrange);
return ans;
}
void work(int id)
{
int u,v;
scanf("%d%d",&u,&v);
u++; v++;
int f1=top[u],f2=top[v],summ=0,maxx=MIN,minn=MAX;
while (f1!=f2)
{
if (deep[f1]<deep[f2]){swap(f1,f2); swap(u,v);}
switch (id)
{
case 1:qf(1,1,n,num[f1],num[u]);break;
case 2:summ+=qsum(1,1,n,num[f1],num[u]);break;
case 3:maxx=max(maxx,qmax(1,1,n,num[f1],num[u]));break;
case 4:minn=min(minn,qmin(1,1,n,num[f1],num[u]));break;
}
u=fa[f1];
f1=top[u];
}
if (u!=v)
{
if (deep[u]<deep[v]) swap(u,v);
switch (id)
{
case 1:qf(1,1,n,num[son[v]],num[u]);break;
case 2:summ+=qsum(1,1,n,num[son[v]],num[u]);printf("%d\n",summ);break;
case 3:maxx=max(maxx,qmax(1,1,n,num[son[v]],num[u]));printf("%d\n",maxx);break;
case 4:minn=min(minn,qmin(1,1,n,num[son[v]],num[u]));printf("%d\n",minn);break;
}
}
else
{
switch(id)
{
case 2:printf("%d\n",summ);break;
case 3:printf("%d\n",maxx);break;
case 4:printf("%d\n",minn);break;
}
}
}
int main()
{
scanf("%d",&n);
for (i=1;i<=n-1;i++) //景点编号为1-N
{
scanf("%d%d%d",&a,&b,&w[i].z);
a++;b++;
addline(a,b);
w[i].a=a; w[i].b=b;
}
dfs_1(1,1,0);
dfs_2(1,0);
for (i=1;i<=n-1;i++)
if (deep[w[i].a]<deep[w[i].b])//权值落在深点上
ww[w[i].b]=w[i].z;
else
ww[w[i].a]=w[i].z;
for (i=1;i<=n;i++) tree[num[i]]=i;
build(1,1,n);
scanf("%d",&m);
for (i=1;i<=m;i++)
{
char st[10];int www,u,v;
scanf("%s",st);
if (st[0]=='C')//变值
{
scanf("%d%d",&x,&www);
change(1,1,n,num[x+1],www);
}
else
if (st[0]=='N')//取反
work(1);
else
if (st[0]=='S')//求和
work(2);
else
if (st[1]=='A')//最大
work(3);
else//最小
work(4);
}
}