#include
#include
#include
#include
#include
#pragma comment(linker, "/STACK:10240000000,10240000000")//手动开大栈区
#define lson rt*2
#define rson rt*2+1
#define mid (l+r)/2
using namespace std;
const int N=100050;
typedef long long ll;
int head[N],to[N*2],next[N*2],fa[N][35],cnt;
void add(int f,int t)
{
next[++cnt]=head[f];
to[cnt]=t;
head[f]=cnt;
}
//
int n,q,a,b,c;
ll d;
//
int son[N],size[N],dep[N];
void dfs1(int rt)
{
size[rt]=1;
int flag=0;
for(int i=head[rt];i!=-1;i=next[i])
{
dep[to[i]]=dep[rt]+1;
dfs1(to[i]);
size[rt]+=size[to[i]];
if(size[to[i]]>flag)
flag=size[to[i]],son[rt]=to[i];
}
}
int zhe[N],fan[N],mx[N],top[N],num;
void dfs2(int rt,int root)
{
top[rt]=root;
zhe[rt]=++num;
fan[num]=rt;
if(son[rt])
dfs2(son[rt],root);
for(int i=head[rt];i!=-1;i=next[i])
if(to[i]!=son[rt])
dfs2(to[i],to[i]);
mx[rt]=num;
}
//
void init()
{
for(int j=1;j<=30;j++)
for(int i=1;i<=n;i++)
if(fa[i][j-1]!=0)
fa[i][j]=fa[fa[i][j-1]][j-1];
}
int er[31]={1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768,65536,131072,262144,524288,1048576,2097152,4194304,8388608,16777216,33554432,67108864,134217728,268435456,536870912,1073741824};
int lca(int u,int v)
{
if(dep[u]=0;i--)
{
if(x>=er[i])
u=fa[u][i],x-=er[i];
}
if(u==v)
return u;
for(int i=31;i>=0;i--)
if(fa[u][i]!=fa[v][i])
u=fa[u][i],v=fa[v][i];
return fa[u][0];
}
struct node
{
ll sum,flag;
}tree[4*N];
void pushup(int rt)
{
tree[rt].sum=tree[lson].sum+tree[rson].sum;
}
void pushdown(int rt,int l,int r)
{
if(!tree[rt].flag)
return ;
tree[lson].sum+=(mid-l+1)*tree[rt].flag;
tree[rson].sum+=(r-mid)*tree[rt].flag;
tree[lson].flag+=tree[rt].flag;
tree[rson].flag+=tree[rt].flag;
tree[rt].flag=0;
}
void ins(int rt,int l,int r,int L,int R,ll x)
{
if(l==L&&r==R)
{
tree[rt].sum+=(r-l+1)*x;
tree[rt].flag+=x;
return ;
}
pushdown(rt,l,r);
if(mid>=R)
ins(lson,l,mid,L,R,x);
else if(middep[aim])
ins(1,1,n,zhe[top[u]],zhe[u],x),u=fa[top[u]][0];
else
ins(1,1,n,zhe[aim],zhe[u],x),u=aim,cnt1++;
}
while(v!=aim)
{
if(dep[top[v]]>dep[aim])
ins(1,1,n,zhe[top[v]],zhe[v],x),v=fa[top[v]][0];
else
ins(1,1,n,zhe[aim],zhe[v],x),v=aim,cnt1++;
}
if(cnt1==0)
ins(1,1,n,zhe[aim],zhe[aim],x);
else if(cnt==2)
ins(1,1,n,zhe[aim],zhe[aim],-x);
}
ll query(int rt,int l,int r,int L,int R)
{
if(l==L&&r==R)
return tree[rt].sum;
pushdown(rt,l,r);
if(mid>=R)
return query(lson,l,mid,L,R);
else if(mid
#include
#include
#include
#include
#include
#define lson rt*2
#define rson rt*2+1
#define mid (l+r)/2
using namespace std;
const int N=100050;
int n;
int head[N],to[N*2],next[2*N],v2[2*N],v1[2*N],id[2*N],fan[N],cnt;
void add(int f,int t,int val,int hao)
{
to[++cnt]=t;
id[cnt]=hao;
v1[cnt]=val;
next[cnt]=head[f];
head[f]=cnt;
}
int a,b,c;
int size[N],son[N];
int fa[N][25];
int s[25],dep[N];
void dfs1(int x)
{
dep[x]=dep[fa[x][0]]+1;
size[x]=1;
for(int i=1;i<=16;i++)
{
if(s[i]>=dep[x])
break;
fa[x][i]=fa[fa[x][i-1]][i-1];
}
for(int i=head[x];i!=-1;i=next[i])
{
if(to[i]==fa[x][0])
continue;
fa[to[i]][0]=x;
fan[id[i]]=to[i];
v2[to[i]]=v1[i];
dfs1(to[i]);
size[x]+=size[to[i]];
if(size[to[i]]>size[son[x]])
son[x]=to[i];
}
}
int zhe[N],top[N],num;
void dfs2(int x,int root)
{
zhe[x]=++num;
top[x]=root;
if(son[x])
dfs2(son[x],root);
for(int i=head[x];i!=-1;i=next[i])
if(to[i]!=son[x]&&to[i]!=fa[x][0])
dfs2(to[i],to[i]);
}
int lca(int u,int v)
{
if(dep[u]=0;i--)
if(cha&s[i])
u=fa[u][i];
if(u==v)
return v;
for(int i=16;i>=0;i--)
if(fa[u][i]!=fa[v][i])
u=fa[u][i],v=fa[v][i];
return fa[u][0];
}
struct node
{
int mx,flag,flah;
}tree[N*8];
void pushup(int rt)
{
tree[rt].mx=max(tree[lson].mx,tree[rson].mx);
}
void pushdown(int rt,int l,int r)
{
if(!tree[rt].flag&&tree[rt].flah==-1)
return;
if(l==r)
return ;
if(tree[rt].flah!=-1)
{
tree[lson].flag=tree[rson].flag=0;
tree[lson].flah=tree[rson].flah=tree[rt].flah;
tree[lson].mx=tree[rson].mx=tree[rt].flah;
tree[rt].flah=-1;
}
tree[lson].flag+=tree[rt].flag;
tree[rson].flag+=tree[rt].flag;
tree[lson].mx+=tree[rt].flag;
tree[rson].mx+=tree[rt].flag;
tree[rt].flag=0;
}
void ins1(int rt,int l,int r,int pos,int val)
{
pushdown(rt,l,r);
if(l==r)
{
tree[rt].mx=val;
return ;
}
if(mid=pos)
ins1(lson,l,mid,pos,val);
pushup(rt);
}
void ins2(int rt,int l,int r,int L,int R,int val)
{
pushdown(rt,l,r);
if(l==L&&r==R)
{
tree[rt].flag+=val;
tree[rt].mx+=val;
return ;
}
if(mid>=R)
ins2(lson,l,mid,L,R,val);
else if(mid=R)
ins3(lson,l,mid,L,R,val);
else if(mid=R)
return query(lson,l,mid,L,R);
else if(mid
#include
#include
#include
#include
#include
#define lson rt*2
#define rson rt*2+1
#define mid (l+r)/2
using namespace std;
const int N=100050;
typedef long long ll;
int m,n;
int head[N],next[2*N],to[2*N],cnt;
void add(int f,int t)
{
to[++cnt]=t;
next[cnt]=head[f];
head[f]=cnt;
}
ll v[N];
int a,b;
ll c;
struct node
{
ll sum,flag;
}tree[N*4];
ll size[N];
int son[N],fa[N];
void dfs1(int rt,int last)
{
ll flag=0;
size[rt]=1;
for(int i=head[rt];i!=-1;i=next[i])
{
if(to[i]==last)
continue;
fa[to[i]]=rt;
dfs1(to[i],rt);
size[rt]+=size[to[i]];
if(size[to[i]]>flag)
flag=size[to[i]],son[rt]=to[i];
}
}
int num,fan[N],zhe[N],top[N],mx[N];
ll vl[N];
void dfs2(int rt,int root)
{
zhe[rt]=++num;
fan[num]=rt;
vl[num]=v[rt];
top[rt]=root;
if(son[rt])
dfs2(son[rt],root);
for(int i=head[rt];i!=-1;i=next[i])
if(to[i]!=fa[rt]&&to[i]!=son[rt])
dfs2(to[i],to[i]);
mx[rt]=num;
}
void pushup(int rt)
{
tree[rt].sum=tree[lson].sum+tree[rson].sum;
}
void pushdown(int rt,int l,int r)
{
tree[lson].sum+=(mid-l+1)*tree[rt].flag;
tree[rson].sum+=(r-mid)*tree[rt].flag;
tree[lson].flag+=tree[rt].flag;
tree[rson].flag+=tree[rt].flag;
tree[rt].flag=0;
}
void build(int rt,int l,int r)
{
if(l==r)
{
tree[rt].sum=vl[l];
return ;
}
build(lson,l,mid);
build(rson,mid+1,r);
pushup(rt);
}
void ins(int rt,int l,int r,int L,int R,ll x)
{
if(l==L&&r==R)
{
tree[rt].sum+=(r-l+1)*x;
tree[rt].flag+=x;
return ;
}
pushdown(rt,l,r);
if(mid=R)
ins(lson,l,mid,L,R,x);
else
ins(lson,l,mid,L,mid,x),ins(rson,mid+1,r,mid+1,R,x);
pushup(rt);
}
ll query(int rt,int l,int r,int L,int R)
{
if(l==L&&r==R)
return tree[rt].sum;
pushdown(rt,l,r);
if(R<=mid)
return query(lson,l,mid,L,R);
else if(mid
清华大佬gconeice的题解:
显然,暴力求解的复杂度是无法承受的。
考虑这样的一种暴力,我们把 z 到根上的点全部打标记,对于 l 到 r 之间的点,向上搜索到第一个有标记的点求出它的深度统计答案。观察到,深度其实就是上面有几个已标记了的点(包括自身)。所以,我们不妨把 z 到根的路径上的点全部 +1,对于 l 到 r 之间的点询问他们到根路径上的点权和。仔细观察上面的暴力不难发现,实际上这个操作具有叠加性,且可逆。也就是说我们可以对于 l 到 r 之间的点 i,将 i 到根的路径上的点全部 +1, 转而询问 z 到根的路径上的点(包括自身)的权值和就是这个询问的答案。把询问差分下,也就是用 [1, r] − [1, l − 1] 来计算答案,那么现在我们就有一个明显的解法。从 0 到 n − 1 依次插入点 i,即将 i 到根的路径上的点全部+1。离线询问答案即可。我们现在需要一个数据结构来维护路径加和路径求和,显然树链剖分或LCT 均可以完成这个任务。树链剖分的复杂度为 O((n + q)· log n · log n),LCT的复杂度为 O((n + q)· log n),均可以完成任务。至此,题目已经被我们完美解决。(摘自 hzwer.com)
实在是太妙了啊啊啊在下不得不orz
#include
#include
#include
#include
#include
#include
#define lson rt*2
#define rson rt*2+1
#define mid (l+r)/2
using namespace std;
const int N=50050;
const int mo=201314;
int ans[N];
int n,q,num;
int l,r,z;
struct state
{
int loc,zz;
};
vector jan[N],jia[N];
int head[N],to[N],next[N],cnt;
void add(int f,int t)
{
to[++cnt]=t;
next[cnt]=head[f];
head[f]=cnt;
}
int fa[N];
int size[N],son[N],zhe[N],dui[N],top[N];
void dfs1(int x)
{
size[x]=1;
int flag=0;
for(int i=head[x];i!=-1;i=next[i])
{
dfs1(to[i]);
size[x]+=size[to[i]];
if(size[to[i]]>flag)
{
flag=size[to[i]];
son[x]=to[i];
}
}
}
void dfs2(int x,int root)
{
zhe[x]=++num;
dui[num]=x;
top[x]=root;
if(son[x])
dfs2(son[x],root);
for(int i=head[x];i!=-1;i=next[i])
if(to[i]!=son[x])
dfs2(to[i],to[i]);
}
struct node
{
int sum;
int flag;
}tree[N*4];
void pushup(int rt)
{
tree[rt].sum=(tree[lson].sum+tree[rson].sum)%mo;
}
void pushdown(int rt,int l,int r)
{
if(!tree[rt].flag)
return ;
tree[lson].flag+=tree[rt].flag;
tree[rson].flag+=tree[rt].flag;
tree[lson].sum=(tree[lson].sum+(tree[rt].flag*(mid-l+1))%mo)%mo;
tree[rson].sum=(tree[rson].sum+(tree[rt].flag*(r-mid))%mo)%mo;
tree[rt].flag=0;
}
void ins(int rt,int l,int r,int L,int R)
{
if(l==L&&r==R)
{
tree[rt].sum=(tree[rt].sum+(r-l+1))%mo;
tree[rt].flag+=1;
return ;
}
pushdown(rt,l,r);
if(mid>=R)
ins(lson,l,mid,L,R);
else if(mid=R)
return query(lson,l,mid,L,R)%mo;
else if(mid
bzoj3531
题意:
一棵树,每个树有一种颜色和一个权值,现在有四种操作:
1.改变一个节点的权值
2.改变一个节点的颜色
3.询问从u到v(保证u,v颜色相同)这条路上与uv颜色相同的点的权值总和
4.询问从u到v(也保证u,v颜色相同)这条路上与uv颜色相同的点的权值最大值
要点:
1.怎么判断是不是颜色相同?
我学会了特殊的开多个线段树的技巧,我会假装四处看风景!
好吧不是什么特殊的,就是这个题需要为每个宗教开一个线段树,而我终于掌握了这种技巧。。。
#include
#include
#include
#include
#include
#define mid (l+r)/2
using namespace std;
const int N=100050;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int n,m,a,b;
int head[N],to[2*N],next[2*N],cnt;
void add(int f,int t)
{
to[++cnt]=t;
next[cnt]=head[f];
head[f]=cnt;
}
int s[N];
int T[N],w[N];
int fa[N][25];
int son[N],size[N];
int dep[N];
void dfs1(int x)
{
dep[x]=dep[fa[x][0]]+1;
for(int i=1;i<=16;i++)
{
if(s[i]>dep[x])
break;
fa[x][i]=fa[fa[x][i-1]][i-1];
}
size[x]=1;
int flag=0;
for(int i=head[x];i!=-1;i=next[i])
{
if(to[i]==fa[x][0])
continue;
fa[to[i]][0]=x;
dfs1(to[i]);
size[x]+=size[to[i]];
if(size[to[i]]>flag)
flag=size[to[i]],son[x]=to[i];
}
}
int zhe[N],top[N],num;
void dfs2(int x,int root)
{
zhe[x]=++num;
top[x]=root;
if(son[x])
dfs2(son[x],root);
for(int i=head[x];i!=-1;i=next[i])
if(to[i]!=son[x]&&to[i]!=fa[x][0])
dfs2(to[i],to[i]);
}
int lca(int u,int v)
{
if(dep[u]=0;i--)
if(cha&s[i])
u=fa[u][i];
if(u==v)
return u;
for(int i=16;i>=0;i--)
if(fa[u][i]!=fa[v][i])
u=fa[u][i],v=fa[v][i];
return fa[u][0];
}
struct node
{
int sum,mx,ls,rs;
}tree[100*N];
void pushup(int rt)
{
tree[rt].sum=tree[tree[rt].ls].sum+tree[tree[rt].rs].sum;
tree[rt].mx=max(tree[tree[rt].ls].mx,tree[tree[rt].rs].mx);
}
int tot;
int root[N];
void ins(int &rt,int l,int r,int pos,int val)
{
if(!rt)
rt=++tot;
if(l==r)
{
tree[rt].mx=tree[rt].sum=val;
return ;
}
if(pos<=mid)
ins(tree[rt].ls,l,mid,pos,val);
else
ins(tree[rt].rs,mid+1,r,pos,val);
pushup(rt);
}
int querysum(int rt,int l,int r,int L,int R)
{
if(!rt) return 0;
if(l==L&&r==R)
return tree[rt].sum;
if(mid>=R)
return querysum(tree[rt].ls,l,mid,L,R);
else if(mid=R)
return querymax(tree[rt].ls,l,mid,L,R);
else if(mid