[鬼畜 树链剖分 线段树] BZOJ 2814 tree

类似最大子段和去搞 可以把两头看成各有两个接口 然后随意维护十几个值搞搞搞

打了一中午 调了一晚上 发现看错题 改了改 调到睡觉

心累


#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long ll;

inline char nc(){
  static char buf[100000],*p1=buf,*p2=buf;
  if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; }
  return *p1++;
}

inline void read(int &x){
  char c=nc(),b=1;
  for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
  for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}

inline void read(char *s){
  char c=nc(); int len=0;
  for (;!(c>='A' && c<='Z');c=nc());
  for (;(c>='A' && c<='Z') || (c>='a' && c<='z');s[++len]=c,c=nc()); s[++len]=0;
}

const int N=50005;

struct abcd{
  ll val; int len; int nil;
  abcd() { nil=1; }
  abcd(ll val,int len):val(val),len(len),nil(0) { }
  friend abcd operator + (abcd A,abcd B){
    if (A.nil) return B;
    if (B.nil) return A;
    return abcd(A.val+B.val,A.len+B.len);
  }
  bool operator < (const abcd &B) const{
    if (B.nil) return 0;
    if (nil) return 1;
    return val==B.val?len<B.len:val<B.val;
  }
};

struct data{
  abcd ans,maxv[2][2],lmax[2],rmax[2]; int nil;
  data() { nil=1; maxv[0][0]=maxv[1][1]=maxv[0][1]=maxv[1][0]=abcd();}
  void rev(){
    swap(maxv[1][0],maxv[0][1]);
    swap(lmax[0],rmax[0]); swap(lmax[1],rmax[1]);
  }
  friend data operator + (data A,data B){
    if (A.nil) return B;
    if (B.nil) return A;
    data ret; ret.nil=0;
    for (int i=0;i<2;i++)
	for (int j=0;j<2;j++)
	  for (int k=0;k<2;k++)
	    ret.maxv[i][j]=max(ret.maxv[i][j],A.maxv[i][k]+B.maxv[k][j]);
    for (int i=0;i<2;i++){
      ret.lmax[i]=A.lmax[i];
      for (int j=0;j<2;j++)
	ret.lmax[i]=max(ret.lmax[i],A.maxv[i][j]+B.lmax[j]);
    }
    for (int i=0;i<2;i++){
      ret.rmax[i]=B.rmax[i];
      for (int j=0;j<2;j++)
	ret.rmax[i]=max(ret.rmax[i],A.rmax[j]+B.maxv[j][i]);
    }
    ret.ans=max(A.ans,B.ans);
    for (int i=0;i<2;i++)
      ret.ans=max(ret.ans,A.rmax[i]+B.lmax[i]);
    return ret;
  }
};

struct SEG{
  struct node{
    int len,sum,tag; int c[2];
    data D; ll minv[2];
    node(){
      len=sum=0;
      D.nil=1; minv[0]=minv[1]=1LL<<40;
      tag=-1;
    }
    node(ll v0,ll v1,int c0,int c1){
      len=1; tag=-1; c[0]=c0; c[1]=c1;
      sum=v0+v1; minv[1]=v0; minv[0]=v1;
      if (c0==1) v0=-1LL<<40;
      if (c1==1) v1=-1LL<<40;
      D.nil=0;
      D.maxv[0][1]=D.maxv[1][0]=abcd(v0+v1,2);
      D.maxv[0][0]=abcd(v0,1); D.maxv[1][1]=abcd(v1,1);
      D.ans=max(max(abcd(v0,1),abcd(v1,1)),abcd(v0+v1,2));
      D.lmax[0]=D.rmax[0]=max(abcd(v0,1),abcd(v0+v1,2));
      D.lmax[1]=D.rmax[1]=max(abcd(v1,1),abcd(v0+v1,2));
    }
    void cover(int cc){
      if (cc==0){
	if (~len&1){
	  D.maxv[0][0]=D.maxv[1][1]=abcd(sum,len<<1);
	  D.maxv[0][1]=abcd(sum-minv[0],(len<<1)-1);
	  D.maxv[1][0]=abcd(sum-minv[1],(len<<1)-1);
	}
	else{
	  D.maxv[1][0]=D.maxv[0][1]=abcd(sum,len<<1);
	  D.maxv[0][0]=abcd(sum-minv[0],(len<<1)-1);
	  D.maxv[1][1]=abcd(sum-minv[1],(len<<1)-1);
	}
	D.lmax[0]=D.lmax[1]=D.rmax[0]=D.rmax[1]=D.ans=abcd(sum,len<<1);
      }else{
	D.maxv[0][0]=D.maxv[1][1]=D.maxv[0][1]=D.maxv[1][0]=abcd(-1LL<<40,0);
	D.lmax[0]=D.lmax[1]=D.rmax[0]=D.rmax[1]=D.ans=abcd(-1LL<<40,0);
      }
      tag=cc; c[0]=c[1]=cc;
    }
    friend node operator + (const node &A,const node &B){
      node ret;
      ret.len=A.len+B.len;
      ret.sum=A.sum+B.sum;
      for (int i=0;i<2;i++)
	ret.minv[i]=min(A.minv[i],B.minv[i^(A.len&1)]);
      ret.D=A.D+B.D;
      return ret;
    }
  }T[N<<2];
  int M,TH;
  void Build(int n){
    for (M=1,TH=0;M<n+2;M<<=1,TH++);
    for (int i=1;i<=n;i++)
      T[M+i]=node(1,1,0,0);
    for (int i=M-1;i;i--)
      T[i]=T[i<<1]+T[i<<1|1];
  }
  void Pushdown(int rt){
    int p;
    for (int i=TH;i;i--)
      if (T[p=rt>>i].tag!=-1)
      {
	T[p<<1].cover(T[p].tag); T[p<<1|1].cover(T[p].tag);
	T[p].tag=-1;
      }
  }
  void CVal(int s,int v0,int v1){
    Pushdown(s+=M);
    T[s]=node(v0,v1,T[s].c[0],T[s].c[1]);
    while (s>>=1)
      T[s]=T[s<<1]+T[s<<1|1];
  }
  void CColor(int s,int p,int c,int v0,int v1){
    Pushdown(s+=M);
    if (p==0)
      T[s]=node(v0,v1,c,T[s].c[1]);
    else
      T[s]=node(v0,v1,T[s].c[0],c);
    while (s>>=1)
      T[s]=T[s<<1]+T[s<<1|1];
  }
  void Cover(int s,int t,int cc){
    for (Pushdown(s+=M-1),Pushdown(t+=M+1);s^t^1;){
      if (~s&1) T[s^1].cover(cc);
      if ( t&1) T[t^1].cover(cc);
      T[s>>=1]=T[s<<1]+T[s<<1|1];
      T[t>>=1]=T[t<<1]+T[t<<1|1];
    }
    while (s>>=1)
      T[s]=T[s<<1]+T[s<<1|1];
  }
  data Sum(int s,int t){
    data lret,rret;
    for (Pushdown(s+=M-1),Pushdown(t+=M+1);s^t^1;s>>=1,t>>=1){
      if (~s&1) lret=lret+T[s^1].D;
      if ( t&1) rret=T[t^1].D+rret;
    }
    return lret+rret;
  }
}Seg;

struct edge{
  int u,v,next;
}G[N<<1];
int head[N],inum;

inline void add(int u,int v,int p){
  G[p].u=u; G[p].v=v; G[p].next=head[u]; head[u]=p;
}

int fat[N],size[N],depth[N];
int top[N],tid[N],clk;
#define V G[p].v
inline void dfs(int u,int fa){
  fat[u]=fa; size[u]=1; depth[u]=depth[fa]+1;
  for (int p=head[u];p;p=G[p].next)
    if (V!=fa)
      dfs(V,u),size[u]+=size[V];
}

inline void find(int u,int fa,int z){
  int maximum=0,son=0; tid[u]=++clk; top[u]=z;
  for (int p=head[u];p;p=G[p].next)
    if (V!=fa && size[V]>maximum)
      maximum=size[son=V];
  if (son) find(son,u,z);
  for (int p=head[u];p;p=G[p].next)
    if (V!=fa && V!=son)
      find(V,u,V);
}

inline void CC(int u,int v,int cc){
  for (;top[u]!=top[v];u=fat[top[u]]){
    if (depth[top[u]]<depth[top[v]]) swap(u,v);
    Seg.Cover(tid[top[u]],tid[u],cc);
  }
  if (depth[u]>depth[v]) swap(u,v);
  Seg.Cover(tid[u],tid[v],cc);
}

inline abcd SS(int u,int v){
  data lret,rret,tmp;
  abcd ret;
  for (;top[u]!=top[v];){
    if (depth[top[u]]>depth[top[v]]){
      tmp=Seg.Sum(tid[top[u]],tid[u]); tmp.rev();
      lret=lret+tmp; u=fat[top[u]];
    }else{
      tmp=Seg.Sum(tid[top[v]],tid[v]);
      rret=tmp+rret; v=fat[top[v]];
    }
  }
  if (depth[u]<depth[v]){
    tmp=Seg.Sum(tid[u],tid[v]);
    lret=lret+tmp;
  }else{
    tmp=Seg.Sum(tid[v],tid[u]); tmp.rev();
    rret=tmp+rret;
  }
  lret=lret+rret;
  return lret.ans;
}

int n;
int val[N][2];

int main(){
  int Q,iu,iv,ic; char order[10]; abcd ret;
  freopen("t.in","r",stdin);
  freopen("t.out","w",stdout);
  read(n);
  for (int i=1;i<n;i++)
    read(iu),read(iv),add(iu,iv,++inum),add(iv,iu,++inum);
  dfs(1,0); find(1,0,1);
  for (int i=1;i<=n;i++)
    val[i][0]=val[i][1]=1;
  Seg.Build(n);
  read(Q);
  while (Q--){
    read(order);
    if (!strcmp(order+1,"CVal")){
      read(iu); read(iv); read(ic);
      val[iu][iv]=ic;
      Seg.CVal(tid[iu],val[iu][0],val[iu][1]);
    }else if (!strcmp(order+1,"CColor")){
      read(iu); read(iv); read(ic);
      Seg.CColor(tid[iu],iv,ic,val[iu][0],val[iu][1]);
    }else if (!strcmp(order+1,"Cover")){
      read(iu); read(iv); read(ic);
      CC(iu,iv,ic); 
    }else if (!strcmp(order+1,"QMax")){
      read(iu); read(iv);
      ret=SS(iu,iv);
      if (ret.val>0)
	printf("%lld\n",ret.val);
      else
	printf("Bad Request.\n");
    }else if (!strcmp(order+1,"QLen")){
      read(iu); read(iv);
      ret=SS(iu,iv);
      if (ret.val>0)
	printf("%d\n",ret.len);
      else
	printf("0\n");
    }
  }
  return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值