• 【刷题】【省选】HAOI2016_地图_LuoguP3180/LOJ2162_圆方树/树形dp/线段树合并/dsu on tree/树上莫队


    链接

    LuoguP3180

    LOJ2162

    题解

    • 圆方树处理一下。
      • 如果就是裸的圆方树,显然是可以的。每次询问也可以直接查询目标节点的子树。
      • 可不可以优秀一点?
      • 定义一个环中最先被遍历到的点为环的根。其他点可以都直接成为这个根的儿子,因为我们圆方树的根是固定的。于是这个圆方树的方点可以全都扔掉(或者说方点和环的根并起来了)。
    • 接下来就是树形dp问题。
      • 没什么好讲的。
      • 很明显可以莫队,也可以dsu on tree,也可以线段树合并。
      • 其中线段树合并如果牺牲一点空间,可持久化一下(就像SAM里面对endpos集合做的那样),甚至可以让你支持在线查询。

    代码

    #include<bits/stdc++.h>
    #define LL long long
    #define MAXN 150100
    #define MAXAI 1000000
    using namespace std;
    template<typename T>void Read(T &cn)
    {
    	char c;int sig = 1;
    	while(!isdigit(c = getchar()))if(c == '-')sig = -1; cn = c-48;
    	while(isdigit(c = getchar()))cn = cn*10+c-48; cn*=sig;
    }
    template<typename T>void Write(T cn)
    {
    	if(cn < 0) {putchar('-'); cn = 0-cn; }
    	int wei = 0; T cm = 0; int cx = cn%10; cn/=10;
    	while(cn)cm = cm*10+cn%10,cn/=10,wei++;
    	while(wei--)putchar(cm%10+48),cm/=10;
    	putchar(cx+48);
    }
    template<typename T>void Min(T &cn, T cm) {cn = cn < cm ? cn : cm; }
    struct Tree{
    	struct qwe{
    		int a,b,ne;
    		void mk(int cn, int cm, int cx) {a = cn; b = cm; ne = cx; }
    	};
    	qwe a[MAXN*2+1];
    	int alen;
    	int head[MAXN+1];
    	void lian(int cn, int cm) {a[++alen].mk(cn, cm, head[cn]); head[cn] = alen; }
    	void lian_d(int cn, int cm) {lian(cn, cm); lian(cm, cn); }
    	void build() {alen = 0; memset(head,0,sizeof(head)); }
    }T1, T2;
    struct Seg{
    	struct node{
    		int ch[2], ji, ou;
    		void qing() {ch[0] = ch[1] = ji = ou = 0; }
    	};
    	node t[MAXN*25];
    	int tlen;
    	int L, R;
    	int ro[MAXN+1];
    	void build(int cl, int cr) {t[0].qing(); tlen = 0; L = cl; R = cr; memset(ro, 0, sizeof(ro)); }
    	int bing(int cn, int cm, int cl, int cr)
    	{
    		if(!cm) return cn; if(!cn) return cm;
    		if(cl == cr) {
    			int ge1 = 0, ge2 = 0;
    			if(t[cn].ji) ge1 = 1; else if(t[cn].ou) ge1 = 2;
    			if(t[cm].ji) ge2 = 1; else if(t[cm].ou) ge2 = 2;
    			if((ge1 + ge2)&1) {t[cn].ji = 1; t[cn].ou = 0; return cn; }
    			if(!ge1 && !ge2) return 0;
    			t[cn].ji = 0; t[cn].ou = 1; return cn;
    		}
    		int zh = (cl+cr)>>1;
    		t[cn].ch[0] = bing(t[cn].ch[0], t[cm].ch[0], cl, zh);
    		t[cn].ch[1] = bing(t[cn].ch[1], t[cm].ch[1], zh+1, cr);
    		update(cn);
    		return cn;
    	}
    	void update(int cn) {t[cn].ji = t[t[cn].ch[0]].ji+t[t[cn].ch[1]].ji; t[cn].ou = t[t[cn].ch[0]].ou + t[t[cn].ch[1]].ou; }
    	void jia(int &cn, int cm, int l, int r)
    	{
    		if(!cn) t[cn = ++tlen].qing();
    		if(l == r) {if(t[cn].ji) t[cn].ji = 0, t[cn].ou = 1; else t[cn].ji = 1, t[cn].ou = 0; return; }
    		int zh = (l+r)>>1; 
    		if(cm <= zh) jia(t[cn].ch[0], cm, l, zh);
    		else jia(t[cn].ch[1], cm, zh+1, r);
    		update(cn);
    	}
    	int qiu(int cn, int cl, int cr, int l, int r, int cm)
    	{
    		if(!cn) return 0;
    		if(cl <= l && r <= cr) return cm ? t[cn].ji : t[cn].ou;
    		int zh = (l+r)>>1, guo = 0;
    		if(cl <= zh) guo = qiu(t[cn].ch[0], cl, cr, l, zh, cm);
    		if(cr > zh) guo = guo + qiu(t[cn].ch[1], cl, cr, zh+1, r, cm);
    		return guo;
    	}
    	void jia_ou(int cn, int cm) {jia(ro[cn], cm, L, R); }
    	int qiu_ou(int cn, int cm, int cx) {if(cm < L) return 0; return qiu(ro[cn], L, cm, L, R, cx); }
    	void bing_ou(int cn, int cm) {ro[cn] = bing(ro[cn], ro[cm], L, R); }
    }T;
    struct xun{
    	int pos, ci, y, typ, ans;
    	void getit(int cn) {ci = cn; Read(typ); Read(pos); Read(y); }
    };
    int n, m, yan, q;
    int dfn[MAXN+1], low[MAXN+1], zhan[MAXN+1], zlen, shi;
    xun a[MAXN+1];
    int zhi[MAXN+1];
    int xian;
    void tarjan(int cn)
    {
    	dfn[cn] = low[cn] = ++shi;
    	zhan[++zlen] = cn; 
    	for(int i = T1.head[cn];i;i = T1.a[i].ne)
    	{
    		int y = T1.a[i].b;
    		if(dfn[y]) Min(low[cn], dfn[y]);
    		else {
    			int lin = zlen; 
    			tarjan(y); Min(low[cn], low[y]);
    			if(low[y] >= dfn[cn]) {
    				while(zlen != lin) T2.lian(cn, zhan[zlen]), zlen--;
    			}
    		}
    	}
    }
    void dfs1(int cn, int fa)
    {
    	for(int i = T2.head[cn];i;i = T2.a[i].ne) if(T2.a[i].b != fa) dfs1(T2.a[i].b, cn);
    	dfn[cn] = ++shi;
    }
    void dfs2(int cn, int fa)
    {
    //	printf("in dfs2 : cn = %d fa = %d
    ",cn,fa);
    	for(int i = T2.head[cn];i;i = T2.a[i].ne)
    	{
    		int y = T2.a[i].b;
    		if(y == fa) continue;
    		dfs2(y, cn);
    		T.bing_ou(cn, y);
    	}
    	T.jia_ou(cn, zhi[cn]);
    	while(xian < q && a[xian+1].pos == cn) ++xian, a[xian].ans = T.qiu_ou(cn, a[xian].y, a[xian].typ);
    }
    int Cmp1(xun cn, xun cm) {return dfn[cn.pos] < dfn[cm.pos]; }
    int Cmp2(xun cn, xun cm) {return cn.ci < cm.ci; }
    int main()
    {
    //	freopen("map.in","r",stdin);
    //	freopen("map.out","w",stdout);
    	Read(n); Read(m); T1.build(); T2.build();
    	for(int i = 1;i<=n;i++) Read(zhi[i]);
    	for(int i = 1;i<=m;i++) {int bx, by; Read(bx); Read(by); T1.lian_d(bx,by); }
    	shi = zlen = 0; memset(dfn,0,sizeof(dfn)); tarjan(1);
    	shi = 0; dfs1(1, 0); T.build(1, MAXAI);
    	Read(q);
    	for(int i = 1;i<=q;i++) a[i].getit(i);
    	sort(a+1, a+q+1, Cmp1);
    	xian = 0; dfs2(1, 0);
    	sort(a+1, a+q+1, Cmp2);
    	for(int i = 1;i<=q;i++) Write(a[i].ans), puts("");
    	return 0;
    }
    
  • 相关阅读:
    Oracle 导入导出 dmp 文件
    zTree树
    下拉复选框
    jQuery Pagination分页插件
    下载java生成PDF
    Activiti 流程实例、任务、执行对象及相关的表
    Activiti 删除key值相同的所有不同版本的流程定义
    Activiti 查询最新版本的流程定义
    Activiti 查看流程图
    Activiti 删除流程定义
  • 原文地址:https://www.cnblogs.com/czyarl/p/13061274.html
Copyright © 2020-2023  润新知