【福建集训】果树

题意

  有一棵 \(n\) 个点的树,每个点有一种 \([1,n]\) 内的整数颜色 \(c_i\),求有多少条不含重复颜色的路径(即路径上不能有两点颜色一样。当然,一个点也是一条合法路径)。
  \(n\le 10^5\)

题解

  我 只 会 点 分 治
  考试时先睡了一小时觉,然后再看这题,想了半天发现是个 sb 题,又感觉其他两题都做不来,于是自信码农起来。
  结果 zjr 不到 1h 就写完了这题 200 多行代码还 A 了,我 1h 写完后调了 3h,心态崩了……
  后来才发现这题标解根本不是点分治,大概是扫描线+线段树……写得比我还简单……我菜得没救了,,,
  顺便吐槽一下这种题暴力分好多啊,以后谁还自信当码农

扫描线+线段树

  对于颜色的限制 等价于 \(O(Tn)\)(本题中 \(T\le 20\))组形如 “\(u,v\) 这两点不能同时出现在路径上” 的限制。
  把一条路径 \((u,v)\) 对应到 \(n\times n\) 的二维平面上的点 \((dfn_u,dfn_v)\),则一条限制等价于二维平面上的 \(1\)\(2\) 个障碍矩形。
  最后就是求二维平面上有多少个点不被任何一个障碍矩形覆盖。扫描线+线段树做即可,复杂度 \(O(Tn\log n)\)
  我又忘了这种基础操作了,我在想什么啊,zbl

我的傻逼点分治

  太恶心了,代码都是我糊出来的,不想细讲……
  大概就是开两棵线段树,一棵记录以某个点为根的子树中有多少个点不能作为另一端点,另一棵记录某个点是否能作为另一端点。
  实际上也可能不要线段树?我说了代码是糊的,我自己都不知道咋蒙过的
  复杂度 \(O(Tn\log^2 n)\),理论上被标解吊打,实际上可能跑得比标解快……

#include
#define ll long long
#define N 200005
#define inf 2147483647
using namespace std;
inline int read(){
    int x=0; bool f=1; char c=getchar();
    for(;!isdigit(c); c=getchar()) if(c=='-') f=0;
    for(; isdigit(c); c=getchar()) x=(x<<3)+(x<<1)+(c^'0');
    if(f) return x;
    return 0-x;
}
int n,c[N]; ll ans;
struct edge{int v,nxt;}e[N<<1];
int hd[N],cnt;
inline void add(int u, int v){e[++cnt]=(edge){v,hd[u]}, hd[u]=cnt;}
int Siz,rt,rt_mxson,siz[N];
void getRoot(int u, int fa){
    siz[u]=1; int mxson=0;
    for(int i=hd[u]; i; i=e[i].nxt) if(~e[i].v && e[i].v!=fa)
        getRoot(e[i].v,u), siz[u]+=siz[e[i].v], mxson=max(mxson,siz[e[i].v]);
    mxson=max(mxson,Siz-siz[u]);
    if(mxson>1;
        pushdown(o,l,r,mid);
        if(L<=mid) mdf(ls,l,mid,L,R,v);
        if(R>mid) mdf(rs,mid+1,r,L,R,v);
        pushup(o);
    }
    int query(int o, int l, int r, int L, int R){
        if(L<=l && r<=R) return sum[o];
        int mid=l+r>>1, ret=0;
        pushdown(o,l,r,mid);
        if(L<=mid) ret+=query(ls,l,mid,L,R);
        if(R>mid) ret+=query(rs,mid+1,r,L,R);
        return ret;
    }
    #undef ls
    #undef rs
}sgt1,sgt2;
  
int suf_sum;
int dfn[N],idx,siz2[N]; vector p[N];
void dfs1(int u, int fa){
    dfn[u]=++idx, siz2[u]=1;
    for(int i=hd[u]; i; i=e[i].nxt) if(~e[i].v && e[i].v!=fa) dfs1(e[i].v,u), siz2[u]+=siz2[e[i].v];
}
bool flag[N][21]; int val[N][21],vis[N];
int V;
void dfs2(int u, int fa){
    int x;
    for(int i=0; i

  
天天就会点分治,分到亲马不认 srO

你可能感兴趣的:(【福建集训】果树)