您的位置:首页 > 其它

bzoj 2243 树链剖分 染色

2015-06-03 23:38 405 查看

2243: [SDOI2011]染色

Time Limit: 20 Sec Memory Limit: 512 MB

Submit: 3205 Solved: 1238

[Submit][Status][Discuss]

Description

给定一棵有n个节点的无根树和m个操作,操作有2类:

1、将节点a到节点b路径上所有点都染成颜色c;

2、询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“112221”由3段组成:“11”、“222”和“1”。

请你写一个程序依次完成这m个操作。

Input

第一行包含2个整数n和m,分别表示节点数和操作数;

第二行包含n个正整数表示n个节点的初始颜色

下面行每行包含两个整数x和y,表示x和y之间有一条无向边。

下面行每行描述一个操作:

“C a b c”表示这是一个染色操作,把节点a到节点b路径上所有点(包括a和b)都染成颜色c;

“Q a b”表示这是一个询问操作,询问节点a到节点b(包括a和b)路径上的颜色段数量。

Output

对于每个询问操作,输出一行答案。

Sample Input

6 5

2 2 1 2 1 1

1 2

1 3

2 4

2 5

2 6

Q 3 5

C 2 1 1

Q 3 5

C 5 1 2

Q 3 5

Sample Output

3

1

2

HINT

数N<=10^5,操作数M<=10^5,所有的颜色C为整数且在[0, 10^9]之间。

Source

第一轮day1
#include <iostream>
#include<stdio.h>
#include<algorithm>
#include<string.h>
using namespace std;
//siz[v]表示以v为根的子树的节点数
//dep[v]表示v的深度(根深度为1)
//top[v]表示v所在的链的顶端节点
//fa[v]表示v的父亲
//son[v]表示与v在同一重链上的v的儿子节点(姑且称为重儿子)
//tid[v]表示v与其父亲节点的连边(姑且称为v的父边)在线段树中的位置
const int maxn=500010;
int n;
int siz[maxn],dep[maxn],top[maxn],fa[maxn],son[maxn];
int tid[maxn];
int tim;
int col[maxn];
int rank[maxn];
struct node
{
int v;
int next;
int w;
}e[maxn*2];
int pre[maxn],cnt;
void init()
{
cnt=0;
tim=0;
memset(pre,-1,sizeof(pre));
memset(son,-1,sizeof(son));
}
void add(int u,int v)
{
e[cnt].v=v;
e[cnt].next=pre[u];
pre[u]=cnt++;
}
//树链剖分部分
void dfs1(int u,int father,int d)//求出dep,fa,siz,son
{
dep[u]=d;
fa[u]=father;
siz[u]=1;
for(int i=pre[u];i!=-1;i=e[i].next)
{
int v=e[i].v;
if(v==father) continue;
dfs1(v,u,d+1);
siz[u]+=siz[v];
if(son[u]==-1||siz[v]>siz[son[u]])
son[u]=v;
}
}
void dfs2(int u,int tp)
{
top[u]=tp;
tid[u]=++tim;
rank[tim]=u;
if(son[u]==-1) return ;
dfs2(son[u],tp);
for(int i=pre[u];i!=-1;i=e[i].next)
{
int v=e[i].v;
if(v!=son[u]&&v!=fa[u])
dfs2(v,v);
}
}
//线段树部分
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
const int inf=1e9;
int num[4*maxn];
int lc[4*maxn];
int rc[4*maxn];
int lazy[4*maxn];
void pushup(int rt)
{
lc[rt]=lc[rt<<1];
rc[rt]=rc[rt<<1|1];
int ans=num[rt<<1]+num[rt<<1|1];
if(rc[rt<<1]==lc[rt<<1|1])
ans--;
num[rt]=ans;
}
void pushdown(int rt)
{
if(lazy[rt])
{
lazy[rt<<1]=lazy[rt<<1|1]=1;
num[rt<<1]=num[rt<<1|1]=1;
lc[rt<<1]=rc[rt<<1]=lc[rt];
lc[rt<<1|1]=rc[rt<<1|1]=lc[rt];
lazy[rt]=0;
}
}
void build(int l,int r,int rt)
{
if(l==r)
{
num[rt]=1;
lc[rt]=col[rank[l]];
rc[rt]=col[rank[r]];
return ;
}
int mid=(l+r)>>1;
build(lson);
build(rson);
pushup(rt);
}
void update(int l,int r,int rt,int L,int R,int val)
{
if(L<=l&&r<=R)
{
lazy[rt]=1;
num[rt]=1;
lc[rt]=rc[rt]=val;
return ;
}
pushdown(rt);
int mid=(l+r)>>1;
if(R<=mid)
update(lson,L,R,val);
else if(L>mid)
update(rson,L,R,val);
else
{
update(lson,L,R,val);update(rson,L,R,val);
}
pushup(rt);
}
int LC,RC;
int query(int l,int r,int rt,int L,int R)
{
if(l==L)
LC=lc[rt];
if(r==R)
RC=rc[rt];
if(L<=l&&R>=r)
return num[rt];
pushdown(rt);
int mid=(l+r)>>1;
if(R<=mid) return query(lson,L,R);
else if(L>mid)
return query(rson,L,R);
else
{
int ans=query(lson,L,R)+query(rson,L,R);
if(rc[rt<<1]==lc[rt<<1|1])
ans--;
return ans;
}

}
int solve(int x,int y,int id,int c)
{
int ans=0;
if(id==1)
{
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]]) swap(x,y);//先搜top深度大的链
update(1,n,1,tid[top[x]],tid[x],c);
x=fa[top[x]];
}
if(dep[x]>dep[y]) swap(x,y);
update(1,n,1,tid[x],tid[y],c);
}
else
{
int ans1=-1,ans2=-1;//记录上次链的左端的颜色 ans1与ans2分别指的两边上次链的左端颜色(接近LCA的那端的颜色)
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]]) {swap(x,y);swap(ans1,ans2);}//ans1始终跟着x跑
ans+=query(1,n,1,tid[top[x]],tid[x]);
if(RC==ans1)
ans--;
ans1=LC;
x=fa[top[x]];
}
if(dep[x]>dep[y]){ swap(x,y);swap(ans1,ans2);}//ans1始终跟着x跑
ans+=query(1,n,1,tid[x],tid[y]);
//注意:因为这里弄反了WA了无数次
if(RC==ans2)
ans--;
if(LC==ans1)
ans--;
return ans;
}
}
int m;
int main()
{
char op[15];
//freopen("in.txt","r",stdin);
while(~scanf("%d%d",&n,&m))
{
init();
for(int i=1;i<=n;i++)
scanf("%d",&col[i]);
for(int i=1;i<n;i++)
{
int u,v;
scanf("%d%d",&u,&v);
add(u,v);
add(v,u);
}
dfs1(1,1,1);
dfs2(1,1);
build(1,n,1);
while(m--)
{
char str[20];
scanf("%s",str);
int u,v,c;
if(str[0]=='C')
{
scanf("%d%d%d",&u,&v,&c);
solve(u,v,1,c);
}
else
{
int u,v;
scanf("%d%d",&u,&v);
printf("%d\n",solve(u,v,2,0));
}
}
}

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