jzoj5678 [GDOI2018Day2 Simulation 4.21] Fruit tree (model transformation, covering line segment tree to find the number of points in the matrix)

Describe

Sister NiroBC is a lively girl. She likes to climb trees very much, and there is a fruit tree in front of her house, which just meets her needs for climbing trees.
This fruit tree has N nodes, and the nodes are labeled 1...N. Each node has a fruit, and the color of the fruit on the ith node is Ci.
Sister NiroBC climbs trees every day, and chooses an interesting path (u,v) to climb every day.
A path is called interesting if and only if the fruits on the path are different colors from each other.
(u,v) and (v,u) are treated as the same path. In particular, (i,i) is also treated as a path, which contains only i as a fruit, which is obviously interesting.
Sister NiroBC wants to know how many interesting paths this tree has.
n<=1e5

Fantastic but classic model transformation

Convert a path to a point (u, v) on a two-dimensional plane.
Consider the situation when the path is illegal. Assuming that there are the same points a and b on it, it is not difficult to find that when a and b are not ancestral relationships, u and v are respectively in They are in two subtrees, otherwise let a be the ancestor of b, p is the closest point to a on the path of ab, one of u and v is in the b subtree, and the other is not in the q subtree.
The subtrees are in the same DFS order, so it is transformed into a matrix covering problem, and how many points are not in the matrix.

There is a classic way to use something called a covered segment treeI won't tell you it's my name, plus scanlines. Each time an interval [a, b] is covered, it is sent to each point according to the line segment tree interval and tagged. For a point, if his tag!=0, it means that he is still covered, otherwise it can be obtained from his son Covered points.

Note that one limitation is that this kind of thing can only be used for overwriting and undoing, and it must be overwritten and then undone. Adding some special judgments should support interval queries.
It's ugly, so be careful with plagiarism.

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N=1e5+10;
int c[N],to[N*2],nex[N*2],final[N],tot;
int f[N][18],dep[N];
int n,vis[N],has[N],L[N],R[N],stm,cnt;
int last[N],xd[N],lazy[4*N],sum[4*N];

long long ans;
void link(int x,int y) {
    to[++tot]=y,nex[tot]=final[x],final[x]=tot;
}
void dfs(int x,int fa) {
    L[x]=++stm;
    f[x][0]=fa; dep[x]=dep[fa]+1;
    for (int i=1; i<18; i++) f[x][i]=f[f[x][i-1]][i-1];
    for (int i=final[x]; i; i=nex[i]) {
        if (to[i]!=fa) dfs(to[i],x);
    }
    R[x]=stm;
}

int lca(int x,int y,int &z) {
    if (dep[x]<dep[y]) swap(x,y);
    for (int i=17; i>=0; i--) if (dep[f[x][i]]>dep[y]) x=f[x][i];
    if (f[x][0]==y) {
        z=x; return f[x][0];
    } else if (dep[x]>dep[y]) x=f[x][0];

    for (int i=17; i>=0; i--) if (f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
    return f[x][0];
}

struct line{
    int x,ly,ry,v;
} le[4*20*N];
bool cmp(line a,line b) {
    return a.x<b.x || a.x==b.x && a.v<b.v;
}
int ltot;
void make(int lx,int rx,int ly,int ry) {
    le[++ltot]=(line) {lx,ly,ry,1};
    le[++ltot]=(line) {rx+1,ly,ry,-1};
}
void make0(int lx,int rx,int ly,int ry) {
    make(lx,rx,ly,ry); make(ly,ry,lx,rx);
}
void update(int x,int sz) {
    if (lazy[x]!=0) sum[x]=sz; else sum[x]=sz==1?0:sum[x*2]+sum[x*2+1];
}
void change(int x,int l,int r,int tl,int tr,int v) {
    if (r<tl || l>tr) return;
    if (tl<=l && r<=tr) {
        lazy[x]+=v;
        update(x,r-l+1);
        return;
    }
    change(x*2,l,l+r>>1,tl,tr,v);
    change(x*2+1,(l+r>>1)+1,r,tl,tr,v);
    update(x,r-l+1);
}
int cnt1,cnt2;
int main() {
    freopen("tree.in","r",stdin);
    freopen("tree.out","w",stdout);
    cin>>n;
    for (int i=1; i<=n; i++) scanf("%d",&c[i]);
    for (int i=1; i<n; i++) {
        int u,v; scanf("%d %d",&u,&v);
        link(u,v),link(v,u);
    }
    dep[1]=1; dfs(1,0);
    for (int i=1; i<=n; i++) {
        if (xd[c[i]]!=0) {
            for (int j=xd[c[i]]; j; j=last[j]) {
                int q=0,g=lca(i,j,q);
                if (q!=0) {
                    cnt2++;
                    int b=(dep[i]>dep[j])?i:j;
                    make0(L[b],R[b],1,L[q]-1);
                    make0(L[b],R[b],R[q]+1,n);
                } else make0(L[i],R[i],L[j],R[j]);
            }
            last[i]=xd[c[i]];
        }
        xd[c[i]]=i;
    }
    le[++ltot]=(line) {1,0,0,0};
    le[++ltot]=(line) {n+1,0,0,0};

    sort(le+1,le+1+ltot,cmp);
    int last=0;
    for (int i=1; i<=ltot; i++) {
        if (le[i].ly<=le[i].ry)
            change(1,1,n,le[i].ly,le[i].ry,le[i].v);

        if (i!=ltot && le[i+1].x!=le[i].x) {
            int jx=le[i+1].x-1;
            ans+=(long long)(jx-(le[i].x-1))*(n-sum[1]);
        }
    }
    cout<<(ans-n)/2+n<<endl;
}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325442657&siteId=291194637