[BJOI2017]树的难题 点分治,线段树合并

[BJOI2017]树的难题

LG传送门

点分治+线段树合并。

我不会写单调队列,所以就写了好写的线段树。

考虑对于每一个分治中心,把出边按颜色排序,这样就能把颜色相同的子树放在一起处理。用一棵动态开点线段树维护颜色不同的子树的信息,另一棵动态开点线段树维护颜色相同的子树的信息,同时按照题目要求更新答案。当子树颜色变化时,就把第二棵线段树合并到第一棵里面去就好了。

代码实现有点繁琐,我调了很久。。。

#include
#include
#include
#include
#include
#define R register
#define I inline
#define Z first
#define Y second
using namespace std;
const int S=200003,M=6000003,inf=0x3f3f3f3f;
char buf[1000000],*p1,*p2;
I char gc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,S,stdin),p1==p2)?EOF:*p1++;}
I int rd(){
    R int f=0,b=1; R char c=gc();
    while((c<48||c>57)&&c!=45) c=gc();
    if(c==45) b=0,c=gc();
    while(c>47&&c<58) f=f*10+(c^48),c=gc();
    return b?f:~f+1;
}
vector > g[S];
struct T{int l,r,f;}a[M];
int c[S],s[S],t[S],h[S],v[S],n,m,e,L,U,u,r,o=-inf,A,B;
I int max(int x,int y){return x>y?x:y;}
I void add(int x,int y,int z){g[x].push_back(make_pair(z,y)),++s[x];}
I void ini(){a[++e].f=-inf,a[e].l=a[e].r=0;}
int mrg(int k,int t){
    if(!k) return t;
    if(!t) return k;
    a[k].f=max(a[k].f,a[t].f),a[k].l=mrg(a[k].l,a[t].l),a[k].r=mrg(a[k].r,a[t].r);
    return k;
}
void ins(int &k,int l,int r,int x,int v){
    if(!k) ini(),k=e;
    if(l==r){a[k].f=max(a[k].f,v); return ;}
    R int m=l+r>>1;
    if(x<=m) ins(a[k].l,l,m,x,v);
    else ins(a[k].r,m+1,r,x,v);
    a[k].f=max(a[a[k].l].f,a[a[k].r].f);
}
int qry(int k,int l,int r,int x,int y){
    if(!k) return -inf;
    if(x<=l&&r<=y) return a[k].f;
    R int m=l+r>>1,o=-inf;
    if(x<=m) o=max(o,qry(a[k].l,l,m,x,y));
    if(mU) return ;
    h[l]=max(h[l],d);
    for(R int i=0,y,z;i

转载于:https://www.cnblogs.com/cj-chd/p/10116932.html

你可能感兴趣的:([BJOI2017]树的难题 点分治,线段树合并)