链接
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;
}