[School training the CSP] AC (heuristic merge tree)

The meaning of problems

A tree, each node \ (I \) has a certain capacity \ (K_i \) (can only be installed \ (K_i \) color); the \ (m \) operations, each time for \ (X \ ) to \ (1 \) all points on the path of a color plus \ (C \) ; interrogate each node after the modify operation is completed how many different colors \ ((n, m, k_i \ leq 10 ^ 5) \)

Thinking

30pts small data directly jump violence

Further there 40pts \ (k_i = 10 ^ 5 \ ) can be compared tail rain


The answer can be seen on a point of impact of its operations in the sub-tree

This problem, apparently either maintain color (range segment tree), or maintenance time (sequential modification operations), and range segment tree can not consider \ (k \) constraints, only 40pts, so consider maintenance time

Thus by modifying the sequence of operations as a subscript segment tree maintenance, a maintenance point of two values: \ (SIZ \) : the number of the sub-tree operation; \ (SUM \) : Number of operating the subtree actually contributes

What is actually contributing to the operation? That same sub-tree, if two of the same color operation has occurred, the operation would take place after that do not contribute, that is, \ (siz + 1 \) but \ (sum \) unchanged

With these two variables, the segment tree according to \ (k_i \) dichotomy can find the \ (i \) node answers

But not every point will build a segment tree, as a point of considering only the operation of its sub-tree , tree line can be combined bottom-up, so he became a tree heuristic merger, to ensure that all the complexity of the operation is not based on heavy son can guarantee no problem complexity

With this question ideas similar, it is to \ (trie \) into the tree line on time

Time complexity \ (O (nlog ^ 2n) \)

Code

#include<bits/stdc++.h>
#define N 100005
#define Min(x,y) ((x)<(y)?(x):(y))
#define Max(x,y) ((x)>(y)?(x):(y))
using namespace std;
typedef long long ll;
int n,m,q,k[N],ans[N];
int sum[N<<2],size[N<<2],sig[N<<2];
int son[N],fa[N],t[N<<2];
vector< pair<int,int> > co[N];
map<int,int> mp;//颜色还有负数,cao 
int colsum=0;

struct Edge
{
    int next,to;
}edge[N<<1];int head[N],cnt=1;

void add_edge(int from,int to)
{
    edge[++cnt].next=head[from];
    edge[cnt].to=to;
    head[from]=cnt;
}
template <class T>
void read(T &x)
{
    char c; int sign=1;
    while((c=getchar())>'9'||c<'0') if(c=='-') sign=-1; x=c-48;
    while((c=getchar())>='0'&&c<='9') x=(x<<1)+(x<<3)+c-48; x*=sign;
}
void dfs1(int rt)
{
    size[rt]=1;
    for(int i=head[rt];i;i=edge[i].next)
    {
        int v=edge[i].to;
        if(v==fa[rt]) continue;
        fa[v]=rt;
        dfs1(v);
        size[rt]+=size[v];
        if(size[son[rt]]<size[v]) son[rt]=v;
    }
}

void pd(int rt)
{
    if(!sig[rt]) return;
    sig[rt<<1]=sig[rt<<1|1]=1;
    size[rt<<1]=size[rt<<1|1]=sum[rt<<1]=sum[rt<<1|1]=0;
    sig[rt]=0;
}
void modify(int rt,int l,int r,int x,int val,int siz)//颜色数量,时间数量 
{
    if(l==r) { sum[rt]+=val; size[rt]+=siz; return; }
    int mid=(l+r)>>1;
    pd(rt);
    if(x<=mid) modify(rt<<1,l,mid,x,val,siz);
    else modify(rt<<1|1,mid+1,r,x,val,siz);
    sum[rt]=sum[rt<<1]+sum[rt<<1|1];
    size[rt]=size[rt<<1]+size[rt<<1|1];
}
int query(int rt,int l,int r,int k)
{
    if(k<=0) return 0;
    if(l==r) return sum[rt];
    int mid=(l+r)>>1;
    pd(rt);
    if(size[rt<<1]<=k) return sum[rt<<1] + query(rt<<1|1,mid+1,r,k-size[rt<<1]);
    return query(rt<<1,l,mid,k);
}
void add(int rt)
{
    for(int i=0,c=co[rt].size();i<c;++i)
    {
        int col=co[rt][i].first,tim=co[rt][i].second;
        if(!t[col])//第一次加入该颜色 
        {
            t[col]=tim;
            modify(1,1,m,tim,1,0);
        }
        else if(t[col]>tim)
        {
            modify(1,1,m,t[col],-1,0);
            modify(1,1,m,tim,1,0);
            t[col]=tim;
        }
        modify(1,1,m,tim,0,1);
    }
}
void clr(int rt)
{
    size[1]=sum[1]=sig[1]=1;
    for(int i=0,c=co[rt].size();i<c;++i) t[co[rt][i].first]=0;
}
void cv(int x,int y)
{
    for(int i=0,c=co[y].size();i<c;++i) co[x].push_back(co[y][i]);
    co[y].clear();
}
void dfs(int rt)
{
    for(int i=head[rt];i;i=edge[i].next)
    {
        int v=edge[i].to;
        if(v==fa[rt] || v==son[rt]) continue;
        dfs(v); clr(v);
    }
    if(son[rt]) dfs(son[rt]);
    add(rt);
    for(int i=head[rt];i;i=edge[i].next)
    {
        int v=edge[i].to;
        if(v==fa[rt] || v==son[rt]) continue;
        add(v);
    }
    ans[rt]=query(1,1,m,k[rt]);
    if(son[rt])
    {
        cv(son[rt],rt);
        swap(co[rt],co[son[rt]]);
//      cv(rt,son[rt]);直接这样复杂度是错的qwq 
        for(int i=head[rt];i;i=edge[i].next)
        {
            int v=edge[i].to;
            if(v!=fa[rt]) cv(rt,v);
        }
    }
}

int main()
{
    freopen("ac.in","r",stdin);
    freopen("ac.out","w",stdout);
    read(n);
    for(int i=1;i<n;++i)
    {
        int x,y;
        read(x);read(y);
        add_edge(x,y);
        add_edge(y,x);
    }
    dfs1(1);
    for(int i=1;i<=n;++i) read(k[i]);
    read(m);
    for(int i=1;i<=m;++i)
    {
        int x,c;
        read(x);read(c);
        if(!mp[c]) mp[c]=++colsum;
        c=mp[c];
        co[x].push_back(make_pair(c,i));
    }
    memset(size,0,sizeof(size));
    dfs(1);
    read(q);
    while(q--)
    {
        int x; read(x);
        printf("%d\n",ans[x]);
    }
    return 0;
}

Guess you like

Origin www.cnblogs.com/Chtholly/p/11762772.html