题目:
题解:
不知道被什么奇奇怪怪的东西卡了好久
一眼就是树剖了啊,但是第二问似乎不友善,由于每次选择了某些链,它们重叠的部分是不能计算的,所以情况比较复杂。
其实转换一下就是标记链上的点,并计算被标记的点的点权和。
由于区间的标记仅为0/1,所以对某段区间打标记时可以再开一个数组维护和。
将每条链对应的每段区间在线段树中标记上,然后统计线段树中所有被标记的点的权值和,最后删除所有点的标记。
树剖+线段树区间修改区间查询,时间复杂度
O(Qklog2n)
O
(
Q
k
l
o
g
2
n
)
至于mod maxlongint,可以使用int自然溢出,最后结果和maxlongint取与。
代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=200005;
int tot,nxt[N*2],point[N],v[N*2],n,size[N],f[N],h[N],in[N],son[N],top[N],num,out[N],have[N*4],sum[N*4],delta[N*4],bb[N*4];
void addline(int x,int y)
{
++tot; nxt[tot]=point[x]; point[x]=tot; v[tot]=y;
++tot; nxt[tot]=point[y]; point[y]=tot; v[tot]=x;
}
void dfs_1(int x,int fa)
{
f[x]=fa; h[x]=h[fa]+1; size[x]=1;int maxx=0;
for (int i=point[x];i;i=nxt[i])
if (v[i]!=fa)
{
dfs_1(v[i],x);
size[x]+=size[v[i]];
if (maxx<size[v[i]]) maxx=size[v[i]],son[x]=v[i];
}
}
void dfs_2(int x,int fa)
{
if (son[fa]!=x) top[x]=x;
else top[x]=top[fa];
in[x]=++num;
if (son[x])
{
dfs_2(son[x],x);
for (int i=point[x];i;i=nxt[i])
if (v[i]!=fa && v[i]!=son[x]) dfs_2(v[i],x);
}
out[x]=num;
}
void updata(int now){sum[now]=sum[now<<1]+sum[now<<1|1];have[now]=have[now<<1]+have[now<<1|1];}
void pushdown(int now,int l,int r,int mid)
{
if (delta[now])
{
delta[now<<1]+=delta[now];
delta[now<<1|1]+=delta[now];
sum[now<<1]+=delta[now]*(mid-l+1);
sum[now<<1|1]+=delta[now]*(r-mid);
delta[now]=0;
}
if (bb[now]!=-1)
{
have[now<<1]=bb[now]*sum[now<<1]; have[now<<1|1]=bb[now]*sum[now<<1|1];
bb[now<<1]=bb[now<<1|1]=bb[now];
bb[now]=-1;
}
}
void change(int now,int l,int r,int lrange,int rrange,int v)
{
if (lrange<=l && rrange>=r) {sum[now]+=v*(r-l+1); delta[now]+=v; return;}
int mid=(l+r)>>1;pushdown(now,l,r,mid);
if (lrange<=mid) change(now<<1,l,mid,lrange,rrange,v);
if (rrange>mid) change(now<<1|1,mid+1,r,lrange,rrange,v);
updata(now);
}
void bj(int now,int l,int r,int lrange,int rrange,int co)
{
if (lrange<=l && rrange>=r) {have[now]=sum[now]*co; bb[now]=co; return;}
int mid=(l+r)>>1;pushdown(now,l,r,mid);
if (lrange<=mid) bj(now<<1,l,mid,lrange,rrange,co);
if (rrange>mid) bj(now<<1|1,mid+1,r,lrange,rrange,co);
updata(now);
}
void Que(int u,int v)
{
int f1=top[u],f2=top[v];
while (f1!=f2)
{
if (h[f1]<h[f2]) swap(f1,f2),swap(u,v);
bj(1,1,n,in[f1],in[u],1);
u=f[f1]; f1=top[u];
}
if (in[u]>in[v]) swap(u,v);
bj(1,1,n,in[u],in[v],1);
}
int main()
{
scanf("%d",&n);
for (int i=1;i<n;i++)
{
int x,y;scanf("%d%d",&x,&y);
addline(x,y);
}
dfs_1(1,0); dfs_2(1,0);
memset(bb,-1,sizeof(bb));
int q,k;scanf("%d",&q);
while(q--)
{
int id,x,v,y;scanf("%d",&id);
if (id==0) scanf("%d%d",&x,&v),change(1,1,n,in[x],out[x],v);
else
{
scanf("%d",&k);
while (k--) scanf("%d%d",&x,&y),Que(x,y);
printf("%d\n",have[1]&0x7fffffff);
bj(1,1,n,1,n,0);
}
}
}