BZOJ3083遥远的国度

3083: 遥远的国度
Time Limit: 10 Sec Memory Limit: 1280 MB
Submit: 2022 Solved: 496
Description
描述
zcwwzdjn在追杀十分sb的zhx,而zhx逃入了一个遥远的国度。当zcwwzdjn准备进入遥远的国度继续追杀时,守护神RapiD阻拦了zcwwzdjn的去路,他需要zcwwzdjn完成任务后才能进入遥远的国度继续追杀。
问题是这样的:遥远的国度有n个城市,这些城市之间由一些路连接且这些城市构成了一颗树。这个国度有一个首都,我们可以把这个首都看做整棵树的根,但遥远的国度比较奇怪,首都是随时有可能变为另外一个城市的。遥远的国度的每个城市有一个防御值,有些时候RapiD会使得某两个城市之间的路径上的所有城市的防御值都变为某个值。RapiD想知道在某个时候,如果把首都看做整棵树的根的话,那么以某个城市为根的子树的所有城市的防御值最小是多少。由于RapiD无法解决这个问题,所以他拦住了zcwwzdjn希望他能帮忙。但zcwwzdjn还要追杀sb的zhx,所以这个重大的问题就被转交到了你的手上。
Input
第1行两个整数n m,代表城市个数和操作数。
第2行至第n行,每行两个整数 u v,代表城市u和城市v之间有一条路。
第n+1行,有n个整数,代表所有点的初始防御值。
第n+2行一个整数 id,代表初始的首都为id。
第n+3行至第n+m+2行,首先有一个整数opt,如果opt=1,接下来有一个整数id,代表把首都修改为id;如果opt=2,接下来有三个整数p1 p2 v,代表将p1 p2路径上的所有城市的防御值修改为v;如果opt=3,接下来有一个整数 id,代表询问以城市id为根的子树中的最小防御值。
Output
对于每个opt=3的操作,输出一行代表对应子树的最小点权值。
Sample Input
3 7
1 2
1 3
1 2 3
1
3 1
2 1 1 6
3 1
2 2 2 5
3 1
2 3 3 4
3 1
Sample Output
1
2
3
4
提示
对于20%的数据,n<=1000 m<=1000。
对于另外10%的数据,n<=100000,m<=100000,保证修改为单点修改。
对于另外10%的数据,n<=100000,m<=100000,保证树为一条链。
对于另外10%的数据,n<=100000,m<=100000,没有修改首都的操作。
对于100%的数据,n<=100000,m<=100000,0<所有权值<=2^31。
Source
zhonghaoxi提供
代码地址:http://paste.ubuntu.com/15308032/
一开始读入的根没有什么卵用。。
操作1:直接换根。。
操作2:修改u到v的路径权值。。
操作3:分类讨论
①root=x,直接查询整棵树的最小值。。
②lca(root,x)!=x,直接查询x的子树的最小值。。
③lca(root,x)=x,先倍增找到与lca最近的点,然后查询补集的最小值。。
这道题我调了一周。。而且还是在Claris神犇的帮助下。。
首先说一下RE和WA的错误点:
①无论是求最小值,还是区间修改、单点修改、区间查询,都要update和pushdown。。
②pushdown的时候要判断是否有标记,若没有则不能pushdown。。
③未考虑到x>y时的情况。。
④写区间修改等操作的时候,一定要清楚传的变量是什么。。
以上问题我纠结了一周。。(有间隔)
感谢Claris神犇。。
附上本蒟蒻的代码:

#include
#include
#include
#include
using namespace std;
int delta[400001]={0},n,m,cnt,sz,a[200001],mx[200001],h[200001],father[200001][17],v[200001],deep[200001],size[200001],pos[200001],belong[200001];
bool vis[200001];
struct data
{
    int to,next;
};
data edge[200001];
struct kx
{
    int value;
};
kx node[400001];

int read()
{
    int w=0,c=1;
    char ch=getchar();
    while (ch<'0' || ch>'9')
      {
        if (ch=='-')
          c=-1;
        ch=getchar();
      }
    while (ch>='0' && ch<='9')
      {
        w=w*10+ch-'0';
        ch=getchar();
      }
    return w*c;
}

void add(int u,int v)
{
    cnt++;
    edge[cnt].next=h[u];
    h[u]=cnt;
    edge[cnt].to=v;
}

void dfs1(int x)
{
    int i;
    size[x]=1;
    vis[x]=true;
    for (i=1;i<=16;i++)
      {
        if (deep[x]<(1<break;
        father[x][i]=father[father[x][i-1]][i-1];
      }
    for (i=h[x];i;i=edge[i].next)
      {
        if (vis[edge[i].to])
          continue;
        deep[edge[i].to]=deep[x]+1;
        father[edge[i].to][0]=x;
        dfs1(edge[i].to);
        size[x]+=size[edge[i].to];
        mx[x]=max(mx[x],mx[edge[i].to]);
      }
}

void dfs2(int x,int chain)
{
    int k=0,i;
    sz++;
    pos[x]=mx[x]=sz;
    belong[x]=chain;
    for (i=h[x];i;i=edge[i].next)
      if (deep[edge[i].to]>deep[x] && size[edge[i].to]>size[k])
        k=edge[i].to;
    if (k==0)
      return;
    dfs2(k,chain);
    mx[x]=max(mx[x],mx[k]);
    for (i=h[x];i;i=edge[i].next)
      if (deep[edge[i].to]>deep[x] && k!=edge[i].to)
        {
            dfs2(edge[i].to,edge[i].to);
            mx[x]=max(mx[x],mx[edge[i].to]);
        }
}

void update(int s)
{
    node[s].value=min(node[s*2].value,node[s*2+1].value);
}

void build(int s,int l,int r)
{
    if (l==r)
      return;
    build(s*2,l,(l+r)/2);
    build(s*2+1,(l+r)/2+1,r);
}

void paint(int s,int z,int l,int r)
{
    node[s].value=z;
    delta[s]=z;
}

void pushdown(int s,int l,int r)
{
    int mid=(l+r)/2;
    paint(s*2,delta[s],l,mid);
    paint(s*2+1,delta[s],mid+1,r);
    delta[s]=0;
}

void change(int s,int l,int r,int x,int y)
{
    int mid=(l+r)/2;
    if (l==x && l==r)
      {
        node[s].value=y;
        return;
      }
    if (delta[s])
      pushdown(s,l,r);
    if (x<=mid)
      change(s*2,l,mid,x,y);
    else
      change(s*2+1,mid+1,r,x,y);
    update(s);
}

void insert(int s,int l,int r,int x,int y,int z)
{
    int mid=(l+r)/2;
    if (x<=l && y>=r)
      {
        paint(s,z,l,r);
        return;
      }
    if (delta[s])
      pushdown(s,l,r);
    if (x<=mid)
      insert(s*2,l,mid,x,y,z);
    if (y>mid)
      insert(s*2+1,mid+1,r,x,y,z);
    update(s);
}

void solveinsert(int x,int y,int z)
{
    for (;belong[x]!=belong[y];x=father[belong[x]][0])
      {
        if (deep[belong[x]]y]])
          swap(x,y);
        insert(1,1,n,pos[belong[x]],pos[x],z);
      }
    if (deep[x]y])
      swap(x,y);
    insert(1,1,n,pos[y],pos[x],z);
}

int querymin(int s,int l,int r,int x,int y)
{
    int mid=(l+r)/2,ans;
    if (x>y)
      return INT_MAX;
    if (x<=l && y>=r)
      return node[s].value;
    if (delta[s])
      pushdown(s,l,r);
    if (x<=mid)
      ans=querymin(s*2,l,mid,x,y);
    else
      ans=INT_MAX;
    if (y>mid)
      ans=min(querymin(s*2+1,mid+1,r,x,y),ans);
    update(s);
    return ans;
}

int lca(int x,int y)
{
    int i,t;
    if (deep[x]y])
      swap(x,y);
    t=deep[x]-deep[y];
    for (i=16;i>=0;i--)
      if (t&(1<x=father[x][i];
    for (i=16;i>=0;i--)
      if (father[x][i]!=father[y][i])
        {
            x=father[x][i];
            y=father[y][i];
        }
    if (x==y)
      return x;
    else
      return father[x][0];
}

int main()
{
    /*freopen("country.in","r",stdin);
    freopen("country.out","w",stdout);*/
    int i,u,v,ask,x,y,z,root,t,hkx,depth;
    n=read(),m=read();
    for (i=1;i<=n-1;i++)
      {
        u=read(),v=read();
        add(u,v),add(v,u);
      }
    for (i=1;i<=n;i++)
      a[i]=read();
    dfs1(1);
    dfs2(1,1);
    build(1,1,n);
    for (i=1;i<=n;i++)
      change(1,1,n,pos[i],a[i]);
    root=read();
    for (i=1;i<=m;i++)
      {
        ask=read(),x=read();
        if (ask==1)
          root=x;
        if (ask==2)
          {
            y=read(),z=read();
            solveinsert(x,y,z);
          }
        if (ask==3)
          {
            t=lca(root,x);
            if (root==x)
              printf("%d\n",querymin(1,1,n,1,n));
            else
              if (t!=x)
                printf("%d\n",querymin(1,1,n,pos[x],mx[x]));
              else
                if (t==x)
                  {
                    hkx=root;
                    depth=deep[root]-deep[x]-1;
                    for (int j=16;j>=0;j--)
                      if (depth&(1<printf("%d\n",min(querymin(1,1,n,1,pos[hkx]-1),querymin(1,1,n,mx[hkx]+1,n)));
                  }
          }
      }
    /*fclose(stdin);
    fclose(stdout);*/
    return 0;
}

你可能感兴趣的:(线段树,树链剖分)