题目
题解
这道题就是把树链剖分中的点标记改成了边的标记,然后我就不会做了;
我么发现,每一个点对应着多个孩子,但是只有一个父亲,于是我们就可以把某个点到父亲的点的边的权值转移到这个点上;
如何防止把最近公共祖先也标记上,这就是树链剖分的一点小变形,找完连头之后左端点+1;
还是对算法理解的不够深刻。
代码
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
#define lson (rt<<1)
#define rson (rt<<1|1)
const int maxn=1e6;
const int inf=1e9;
int read(){
char ch=getchar(); int now=0,f=1;
while (ch<'0'||ch>'9') {
if (ch=='-') f=-1; ch=getchar();}
while (ch>='0'&&ch<='9'){now=(now<<1)+(now<<3)+ch-'0'; ch=getchar();}
return now*f;}
int n,m,fa[maxn],son[maxn],deep[maxn],dfn[maxn],idfn[maxn],top[maxn],tot[maxn];
struct Edge{
int next,to;
}edge[maxn<<1];
int num_edge=-1,head[maxn];
void add_edge(int from,int to)
{
edge[++num_edge].next=head[from];
edge[num_edge].to=to;
head[from]=num_edge;
}
void dfs1(int x,int father,int depth)
{
fa[x]=father;
deep[x]=depth;
tot[x]=1;
int maxnow=-1;
for (int i=head[x]; i!=-1; i=edge[i].next)
{
int to=edge[i].to;
if (to!=father)
{
dfs1(to,x,depth+1);
tot[x]+=tot[to];
if (tot[to]>maxnow)
{
maxnow=tot[to];
son[x]=to;
}
}
}
}
int cnt=0;
void dfs2(int x,int tp)
{
dfn[x]=++cnt;
idfn[cnt]=x;
top[x]=tp;
if (!son[x]) return;
dfs2(son[x],tp);
for (int i=head[x]; i!=-1; i=edge[i].next)
{
int to=edge[i].to;
if (to!=fa[x] && to!=son[x])
dfs2(to,to);
}
}
//Seg_Tree
int sum[maxn<<1|1],add[maxn<<1|1];
void pushup(int rt) {sum[rt]=sum[lson]+sum[rson];}
void pushdown(int rt,int ln,int rn)
{
if (add[rt])
{
add[lson]+=add[rt];
add[rson]+=add[rt];
sum[lson]+=ln*add[rt];
sum[rson]+=rn*add[rt];
add[rt]=0;
}
}
void change(int L,int R,int C,int l,int r,int rt)
{
if (L<=l && r<=R)
{
add[rt]+=C; sum[rt]+=C*(r-l+1);
return;
}
int mid=(l+r)>>1;
pushdown(rt,mid-l+1,r-mid);
if (L<=mid) change(L,R,C,l,mid,lson);
if (R>mid) change(L,R,C,mid+1,r,rson);
pushup(rt);
}
int ques(int L,int R,int l,int r,int rt)
{
if (L<=l && r<=R) return sum[rt];
int mid=(l+r)>>1; int ans=0;
pushdown(rt,mid-l+1,r-mid);
if (L<=mid) ans+=ques(L,R,l,mid,lson);
if (R>mid) ans+=ques(L,R,mid+1,r,rson);
return ans;
}
void Treechange(int x,int y,int k)
{
while (top[x]!=top[y])
{
if (deep[top[x]]<deep[top[y]]) swap(x,y);
change(dfn[top[x]],dfn[x],k,1,n,1);
x=fa[top[x]];
}
if (deep[x]>deep[y]) swap(x,y);//记住和while中的符号不同
change(dfn[x]+1,dfn[y],k,1,n,1);
}
int Treeques(int x,int y)
{
int ans=0;
while (top[x]!=top[y])
{
if (deep[top[x]]<deep[top[y]]) swap(x,y);
ans+=ques(dfn[top[x]],dfn[x],1,n,1);
x=fa[top[x]];
}
if (deep[x]>deep[y]) swap(x,y);
ans+=ques(dfn[x]+1,dfn[y],1,n,1);
return ans;
}
char opt[10];
int main()
{
// freopen("grassplant.in","r",stdin);
// freopen("grassplant.out","w",stdout);
memset(head,-1,sizeof(head));
n=read(); m=read();
for (int i=1; i<n; i++)
{
int x=read(); int y=read();
add_edge(x,y); add_edge(y,x);
}
dfs1(1,1,1);
dfs2(1,1);
for (int i=1; i<=m; i++)
{
scanf("%s",opt); int x=read(); int y=read();
if (opt[0]=='P') Treechange(x,y,1);
else printf("%d\n",Treeques(x,y));
}
}
总结
屡败屡战