【刷题】【省选】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;
}
原文地址:https://www.cnblogs.com/czyarl/p/13061274.html