您的位置:首页 > 其它

bzoj3589 动态树

2017-03-02 21:23 267 查看
题意:给你一棵树,要求你维护两个操作.

0:某子树的所有节点权值加上一个数.

1:求某些链并集的权值和.

对于第一个操作,大力树链剖分加线段树.

对于第二个操作,考虑到链的数量很少,可以容斥.

代码:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<iomanip>
using namespace std;
#define LL long long
#define up(i,j,n) for(int i=j;i<=n;i++)
#define pii pair<int,int>
#define db double
#define eps 1e-4
#define FILE "dealing"
int read(){
int x=0,f=1,ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch<='9'&&ch>='0'){x=(x<<1)+(x<<3)+ch-'0',ch=getchar();}
return x*f;
}
const LL maxn=1000000,inf=1000000000000000LL,limit=20000;
bool cmin(int& a,int b){return a>b?a=b,true:false;}
bool cmax(int& a,int b){return a<b?a=b,true:false;}
int n,m;
struct node{
int y,next;
}e[maxn];
int len=0,linkk[maxn],top[maxn],fa[maxn],dep[maxn],pre[maxn],low[maxn];
void insert(int x,int y){
e[++len].y=y;
e[len].next=linkk[x];
linkk[x]=len;
}
void init(){
n=read();
up(i,1,n-1){
int x=read(),y=read();
insert(x,y);
insert(y,x);
}
}
namespace treepou{
int dfs_clock=0,siz[maxn],son[maxn];
void dfs1(int x){
siz[x]=1;
for(int i=linkk[x];i;i=e[i].next){
if(e[i].y==fa[x])continue;
fa[e[i].y]=x;
dep[e[i].y]=dep[x]+1;
dfs1(e[i].y);
siz[x]+=siz[e[i].y];
if(siz[e[i].y]>siz[son[x]])son[x]=e[i].y;
}
}
void dfs2(int x){
pre[x]=++dfs_clock;
if(son[x]){
top[son[x]]=top[x];
dfs2(son[x]);
}
for(int i=linkk[x];i;i=e[i].next){
if(e[i].y==son[x]||e[i].y==fa[x])continue;
top[e[i].y]=e[i].y;
dfs2(e[i].y);
}
low[x]=dfs_clock;
}
void solve(){
dfs1(1);
top[1]=1;
dfs2(1);
}
};
namespace SegTree{
int del[maxn],siz[maxn],sum[maxn],L,R,key,id[maxn];
int Add(int x,int d){
del[x]+=d;
sum[x]+=siz[x]*d;
}
void updata(int x){
sum[x]=sum[x<<1]+sum[x<<1|1];
}
void pushdown(int x){
if(del[x]){
Add(x<<1,del[x]);
Add(x<<1|1,del[x]);
del[x]=0;
}
}
void change(int o,int l,int r){
if(l>R||r<L)return;
if(l>=L&&r<=R){Add(o,key);return;}
int mid=(l+r)>>1;
pushdown(o);
change(o<<1,l,mid);
change(o<<1|1,mid+1,r);
updata(o);
}
void Change(int x,int y,int Del){
L=x,R=y,key=Del;
change(1,1,n);
}
int query(int l,int r,int o){
if(l>R||r<L)return 0;
if(l>=L&&r<=R)return sum[o];
int mid=(l+r)>>1;
pushdown(o);
return query(l,mid,o<<1)+query(mid+1,r,o<<1|1);
}
int Query(int x,int y){
if(x>y)swap(x,y);
L=x,R=y;
return query(1,n,1);
}
void build(int l,int r,int o){
if(l==r){
siz[o]=1;
sum[o]=0;
return;
}
int mid=(l+r)>>1;
build(l,mid,o<<1);
build(mid+1,r,o<<1|1);
siz[o]=siz[o<<1]+siz[o<<1|1];
}
void Build(){
up(i,1,n)id[pre[i]]=i;
build(1,n,1);
}
}
namespace solve{
pii getlian(int x,int y){
int f1,f2;
int sum=0;
while(true){
if(dep[x]>dep[y])swap(x,y);
f1=top[x],f2=top[y];
if(f1==f2){
sum+=SegTree::Query(pre[x],pre[y]);
return make_pair(x,sum);
}
if(dep[f1]>dep[f2])swap(x,y),swap(f1,f2);
sum+=SegTree::Query(pre[f2],pre[y]);
y=fa[f2];
}
}
int getlca(int x,int y){
int f1,f2;
while(true){
if(dep[x]>dep[y])swap(x,y);
f1=top[x],f2=top[y];
if(f1==f2)return x;
if(dep[f1]>dep[f2])swap(x,y),swap(f1,f2);
y=fa[f2];
}
}
pii t[maxn];
int query(){
int m=read();
up(i,1,m){
t[i].first=read(),t[i].second=read();
if(dep[t[i].first]>dep[t[i].second])swap(t[i].first,t[i].second);
}
pii y=make_pair(0,0);
int ans=0;
for(int i=1;i<(1<<m);i++){
int g=-1,flag=0;
up(j,1,m){
if(i&(1<<j-1))g*=-1;
else continue;
if(!flag)y=t[j],flag=1;
else {
int w=getlca(y.second,t[j].second);

if(dep[w]<dep[y.first]||dep[w]<dep[t[j].first]){
y=make_pair(0,0);
break;
}
else {
if(dep[y.first]<dep[t[j].first])y.first=t[j].first;
y.second=w;
}
}
}
//printf("%d %d %d\n",g,y.first,y.second);
if(y.first)ans+=g*getlian(y.first,y.second).second;
}
return ans;
}
};

int main(){
freopen(FILE".in","r",stdin);
freopen(FILE".out","w",stdout);
init();
treepou::solve();//树剖 返回top,dep,fa
SegTree::Build();//prepare SegTree
int m=read();
while(m--){
int ch=read();
if(ch==0){
int x=read(),del=read();
SegTree::Change(pre[x],low[x],del);
}
else printf("%d\n",solve::query()&((1<<31)-1));
}
return 0;
}


  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: