bzoj 2325: [ZJOI2011]道馆之战 (树链剖分+线段树)

来源:互联网 发布:淘宝电商怎么做 编辑:程序博客网 时间:2024/05/16 02:05

2325: [ZJOI2011]道馆之战

Time Limit: 40 Sec  Memory Limit: 256 MB
Submit: 1175  Solved: 429
[Submit][Status][Discuss]

Description

口袋妖怪(又名神奇宝贝或宠物小精灵)红/蓝/绿宝石中的水系道馆需要经过三个冰地才能到达馆主的面前,冰地中
的每一个冰块都只能经过一次。当一个冰地上的所有冰块都被经过之后,到下一个冰地的楼梯才会被打开。三个冰
地分别如下:
当走出第三个冰地之后,就可以与馆主进行道馆战了。馆主发现这个难度太小,导致经常有挑战者能通过,为了加
大难度,将道馆分成了n个房间,每个房间中是两个冰块或障碍,表示一列冰地。任意两个房间之间均有且仅有一
条路径相连,即这n个房间构成一个树状结构。每个房间分成了A和B两个区域,每一区域都是一个薄冰块或者障碍
物。每次只能移动到相邻房间的同一类区域(即若你现在在这个房间的A区域,那么你只能移动到相邻房间的A区域)
或这个房间的另一区域。现在挑战者从房间u出发,馆主在房间v,那么挑战者只能朝接近馆主所在房间的方向过去
。一开始挑战者可以在房间u的任意一个冰块区域内。如果挑战者踩过的冰块数达到了最大值(即没有一种方案踩过
的冰块数更多了),那么当挑战者走到最后一个冰块上时,他会被瞬间传送到馆主面前与馆主进行道馆战。自从馆
主修改规则后已经经过了m天,每天要么是有一个挑战者来进行挑战,要么就是馆主将某个房间进行了修改。对于
每个来的挑战者,你需要计算出他若要和馆主进行战斗需要经过的冰块数。

Input

第一行包含两个正整数n和m。第2行到第n行,每行包含两个正整数x和y,表示一条连接房间x和房间y的边。房间编
号为1…n。接下来n行,每行包含两个字符。第n + k行表示房间k的两个区域,第一个字符为A区域,第二个字符为
B区域。其中“.”(ASCII码为46)表示是薄冰块,“#”(ASCII码为35)表示是障碍物。最后的m行,每行一个操作:
l C u s:将房间u里的两个区域修改为s。
l Q u v:询问挑战者在房间u,馆主在房间v时,挑战者能与馆主进行挑战需要踩的冰块数。如果房间u的两个区域
都是障碍物,那么输出0。
N≤ 30 000
M ≤ 80 000

Output

包含若干行,每行一个整数。即对于输入中的每个询问,依次输出一个答案。

Sample Input

5 3
1 2
2 3
2 4
1 5
.#
..
#.
.#
..
Q 5 3
C 1 ##
Q 4 5

Sample Output

6
3

HINT

Source

Day2

[Submit][Status][Discuss]

题解:树链剖分+线段树

线段树维护从左上到右上,从左上到右下,从左下到右上,从左下到右下走过冰块的最大值

以及从一段区间的左上,左下,右上,右下出发分别能达到能到达的最远距离。

剩下的就是树链剖分的问题啦。

注意从x->lca(x,y)得到的信息,需要进行适当的调整,再与lca(x,y)->y合并。

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<cmath>#define N 30003#define inf 1000000000using namespace std;struct data{    int l1,l2,r1,r2;    int d1,d2,d3,d4;}tr[N*4];char s[N][3];int n,m,point[N*2],nxt[N*2],v[N*2],tot,sz;int belong[N],pos[N],size[N],q[N],son[N],deep[N],fa[N];void add(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(int x,int f){    size[x]=1;    deep[x]=deep[f]+1;    for (int i=point[x];i;i=nxt[i]){        if (v[i]==f) continue;        fa[v[i]]=x;        dfs(v[i],x);        size[x]+=size[v[i]];        if (size[v[i]]>size[son[x]])         son[x]=v[i];    }}void dfs1(int x,int chain){    pos[x]=++sz; q[sz]=x; belong[x]=chain;    if (!son[x]) return;    dfs1(son[x],chain);    for (int i=point[x];i;i=nxt[i])     if(v[i]!=son[x]&&v[i]!=fa[x])      dfs1(v[i],v[i]);}data update(data x,data y){    data a;     a.d1=max(x.d1+y.d1,x.d2+y.d3); if (a.d1<0) a.d1=-inf;    a.d2=max(x.d2+y.d4,x.d1+y.d2); if (a.d2<0) a.d2=-inf;    a.d3=max(x.d3+y.d1,x.d4+y.d3); if (a.d3<0) a.d3=-inf;    a.d4=max(x.d3+y.d2,x.d4+y.d4); if (a.d4<0) a.d4=-inf;    a.l1=x.l1; a.l2=x.l2; a.r1=y.r1; a.r2=y.r2;    a.l1=max(a.l1,max(x.d1+y.l1,x.d2+y.l2)); if (a.l1<0) a.l1=-inf;    a.l2=max(a.l2,max(x.d4+y.l2,x.d3+y.l1)); if (a.l2<0) a.l2=-inf;    a.r1=max(a.r1,max(y.d1+x.r1,y.d3+x.r2)); if (a.r1<0) a.r1=-inf;    a.r2=max(a.r2,max(y.d2+x.r1,y.d4+x.r2)); if (a.r2<0) a.r2=-inf;     return a;}void build(int now,int l,int r){    if (l==r) {        int x=q[l];        tr[now].d1=tr[now].d2=tr[now].d3=tr[now].d4=-inf;        tr[now].l1=tr[now].l2=tr[now].r1=tr[now].r2=-inf;        if (s[x][0]=='.') tr[now].d1=tr[now].l1=tr[now].r1=1;        if (s[x][1]=='.') tr[now].d4=tr[now].l2=tr[now].r2=1;        if (s[x][1]=='.'&&s[x][0]=='.')         tr[now].d2=tr[now].d3=tr[now].l1=tr[now].l2=tr[now].r1=tr[now].r2=2;        //cout<<tr[now].l1<<" "<<tr[now].l2<<" "<<tr[now].r1<<" "<<tr[now].r2<<endl;        return;    }    int mid=(l+r)/2;    build(now<<1,l,mid);    build(now<<1|1,mid+1,r);    tr[now]=update(tr[now<<1],tr[now<<1|1]);    //cout<<tr[now].l1<<" "<<tr[now].l2<<" "<<tr[now].r1<<" "<<tr[now].r2<<endl;}void pointchange(int now,int l,int r,int pos){    if(l==r) {        int x=q[l];        tr[now].d1=tr[now].d2=tr[now].d3=tr[now].d4=-inf;        tr[now].l1=tr[now].l2=tr[now].r1=tr[now].r2=-inf;        if (s[x][0]=='.') tr[now].d1=tr[now].l1=tr[now].r1=1;        if (s[x][1]=='.') tr[now].d4=tr[now].l2=tr[now].r2=1;        if (s[x][1]=='.'&&s[x][0]=='.')         tr[now].d2=tr[now].d3=tr[now].l1=tr[now].l2=tr[now].r1=tr[now].r2=2;        return;    }    int mid=(l+r)/2;    if (pos<=mid) pointchange(now<<1,l,mid,pos);    else pointchange(now<<1|1,mid+1,r,pos);    tr[now]=update(tr[now<<1],tr[now<<1|1]);    //cout<<tr[now].l1<<" "<<tr[now].l2<<" "<<tr[now].r1<<" "<<tr[now].r2<<endl;}data query(int now,int l,int r,int ll,int rr){    if (ll<=l&&r<=rr) return tr[now];    int mid=(l+r)/2;    if (ll<=mid&&rr>mid) return update(query(now<<1,l,mid,ll,rr),query(now<<1|1,mid+1,r,ll,rr));    else if (ll<=mid) return query(now<<1,l,mid,ll,rr);    else return query(now<<1|1,mid+1,r,ll,rr);}void clear(data &a){    a.d1=a.d2=a.d3=a.d4=0;    a.l1=a.l2=a.r1=a.r2=0;}int solve(int x,int y){    if (s[x][0]=='#'&&s[x][1]=='#') return 0;    data a,b;     clear(a); clear(b);    while (belong[x]!=belong[y]) {        if (deep[belong[x]]>deep[belong[y]]) {            a=update(query(1,1,n,pos[belong[x]],pos[x]),a);            x=fa[belong[x]];        }        else {            b=update(query(1,1,n,pos[belong[y]],pos[y]),b);            y=fa[belong[y]];        }    }    if (deep[x]<deep[y]) b=update(query(1,1,n,pos[x],pos[y]),b);    else a=update(query(1,1,n,pos[y],pos[x]),a);    swap(a.l1,a.r1); swap(a.l2,a.r2); swap(a.d2,a.d3);    a=update(a,b);    return max(a.l1,a.l2);}int main(){    scanf("%d%d",&n,&m);    for (int i=1;i<n;i++) {        int x,y; scanf("%d%d",&x,&y);        add(x,y);    }    dfs(1,0); dfs1(1,1);    for (int i=1;i<=n;i++) scanf("%s",s[i]);    build(1,1,n);    //for (int i=1;i<=n;i++) cout<<pos[i]<<" "; cout<<endl;    //for (int i=1;i<=n;i++) cout<<q[i]<<" "; cout<<endl;    //cout<<tr[1].l1<<" "<<tr[1].l2<<" "<<tr[1].r1<<" "<<tr[1].r2<<endl;    for (int i=1;i<=m;i++) {        char opt[10];        int x,y;         scanf("%s",opt);        if (opt[0]=='Q') {            scanf("%d%d",&x,&y);            printf("%d\n",solve(x,y));        }        else {            scanf("%d",&x);            scanf("%s",s[x]);            pointchange(1,1,n,pos[x]);        }    }}



0 0
原创粉丝点击