[NOIP2017集训日记 2017.9-11]

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[NOIP2017集训日记 2017.9-11]相关的知识,希望对你有一定的参考价值。

前言:

这次NOIP好像考不好就退役?

所以写点日记记录生活 好过什么都没留下 给以后做点怀念

 

2017.9.5

 

This Problem Is Too Simple!

这个超好的题

只要你想到离散化 O(N2logN) 草过是没有什么毛病的

可是你要想到精益求精 所以这样做不好

其实有O(Nlog N)做法

对于每一种颜色的 影响的是以这个点为端点的一条链 然后对于询问x y可以差分出四条链

我们关键是维护一条链怎么办 发现如果这个点+1了 子树内的肯定也+1

那么就是维护一个树状数组 这个点打一个+1标记 这个子树外的第一个点打一个-1标记 然后用树状数组维护前缀和即可

好像常数还没写O(N2logN)好...

技术分享
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

const int Maxn=500010;

struct EDGE{int x,y,next;}edge[Maxn]; int len,first[Maxn];
void ins(int x,int y){len++; edge[len].x=x; edge[len].y=y; edge[len].next=first[x]; first[x]=len;}

struct node1
{
  int t,op,x,c;
  node1(){}
  node1(int _t,int _x,int _c,int _op){t=_t; x=_x; c=_c; op=_op;}
}Q1[Maxn*4]; int Q1len=0;
struct node2
{
  int t,x,y,c;
  node2(){}
  node2(int _t,int _x,int _y,int _c){t=_t; x=_x; y=_y; c=_c;}
}Q2[Maxn*4]; int Q2len=0;

int L[Maxn],R[Maxn],id=0; int fa[Maxn][21],dep[Maxn];

void Dfs(int x,int f)
{
  L[x]=++id;
  for(int k=first[x];k!=-1;k=edge[k].next)
  {
    int y=edge[k].y; if(y==f) continue;
    fa[y][0]=x; dep[y]=dep[x]+1; Dfs(y,x);
  }R[x]=id;
}

bool Cmp1(const node1 &x,const node1 &y)
{
  if(x.c!=y.c) return x.c<y.c;
  return x.t<y.t;
}

bool Cmp2(const node2 &x,const node2 &y)
{
  if(x.c!=y.c) return x.c<y.c;
  return x.t<y.t;
}

bool Cmp3(const node2 &x,const node2 &y){return x.t<y.t;}

int N,q; int preC[Maxn],C[Maxn],Clen=0; int ans[Maxn];

int tr[Maxn]; int low_bit(int x){return x&(-x);}
void Add(int x,int c){while(x<=N){tr[x]+=c; x+=low_bit(x);}}
int Query(int x){int ans=0; while(x>=1){ans+=tr[x]; x-=low_bit(x);} return ans;}
void Del(int x){while(x<=N){tr[x]=0; x+=low_bit(x);}}

int LCA(int x,int y)
{
  if(dep[x]<dep[y]) swap(x,y);
  int deep=dep[x]-dep[y];
  for(int i=20;i>=0;i--) if(deep>=(1<<i)) deep-=(1<<i),x=fa[x][i];
  if(x==y) return x;
  for(int i=20;i>=0;i--) if(fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
  return fa[x][0];
}

int main()
{
  
  scanf("%d%d",&N,&q);
  
  for(int i=1;i<=N;i++) scanf("%d",&preC[i]),C[++Clen]=preC[i];
  for(int i=1;i<=N;i++) Q1[++Q1len]=node1(0,i,preC[i],1);
  
  len=0; memset(first,-1,sizeof(first));
  for(int i=1;i<N;i++){int x,y; scanf("%d%d",&x,&y); ins(x,y); ins(y,x);}
  id=0; dep[1]=1; Dfs(1,0);
  
  for(int j=1;j<=20;j++) for(int i=1;i<=N;i++) fa[i][j]=fa[fa[i][j-1]][j-1];
  
  for(int i=1;i<=q;i++)
  {
    char ch; scanf("\n%c",&ch);
    if(ch==C)
    {
      int x,c; scanf("%d%d",&x,&c); C[++Clen]=c;
      if(c!=preC[x])
      {
        Q1[++Q1len]=node1(i,x,preC[x],-1);
        Q1[++Q1len]=node1(i,x,c,1); preC[x]=c;
      }
    }
    else
    {
      int x,y,c; scanf("%d%d%d",&x,&y,&c);
      Q2[++Q2len]=node2(i,x,y,c); C[++Clen]=c;
    }
  }
  
  sort(Q1+1,Q1+Q1len+1,Cmp1);
  sort(Q2+1,Q2+Q2len+1,Cmp2);
  sort(C+1,C+Clen+1);
  
  Clen=unique(C+1,C+Clen+1)-(C+1);
  int l1=1,l2=1,r1=0,r2=0;
  for(int i=1;i<=Clen;i++)
  {
    int x=C[i];
    while(Q1[r1+1].c==C[i] && r1<=Q1len) r1++;
    while(Q2[r2+1].c==C[i] && r2<=Q2len) r2++;
    
    int last=l1;
    while(l1<=r1 && l2<=r2)
    {
      if(Q1[l1].t<Q2[l2].t)
      {
        Add(R[Q1[l1].x]+1,(-1)*Q1[l1].op); Add(L[Q1[l1].x],1*Q1[l1].op);
        l1++;
      }
      else
      {
        int r=LCA(Q2[l2].x,Q2[l2].y);
        ans[Q2[l2].t]=Query(L[Q2[l2].x])+Query(L[Q2[l2].y])-Query(L[r])-Query(L[fa[r][0]]);
        l2++;
      }
    }
    
    while(l1<=r1) l1++;
    while(l2<=r2)
    {
      int r=LCA(Q2[l2].x,Q2[l2].y);
      ans[Q2[l2].t]=Query(L[Q2[l2].x])+Query(L[Q2[l2].y])-Query(L[r])-Query(L[fa[r][0]]);
      l2++;
    }
    
    while(last<=r1) Del(R[Q1[last].x]+1),Del(L[Q1[last].x]),last++;
  }
  
  sort(Q2+1,Q2+Q2len+1,Cmp3);
  for(int i=1;i<=Q2len;i++) printf("%d\n",ans[Q2[i].t]);
  return 0;
}
View Code

 

以上是关于[NOIP2017集训日记 2017.9-11]的主要内容,如果未能解决你的问题,请参考以下文章

2017 noip赛前集训___整理

2017/10 冲刺NOIP集训记录:为了艾尔!

NOIP 2017 集训散记

2017.10.28noip赛前集训 | T1 差分

2017.11.07noip赛前集训 | T1 遭遇DP

2017.10.30noip赛前集训 | T1 军训排队模拟