AC日记——Count on a tree II spoj

Count on a tree II

思路:

  树上莫队;

  先分块,然后,就好办了;

来,上代码:

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

#define maxn 40005
#define maxm 100005

struct QueryType {
    int u,v,id;
};
struct QueryType qu[maxm];

int n,m,ti[maxn],num[maxn],Hash[maxn],siz;
int bel[maxn],f[maxn],deep[maxn],ans[maxm];
int E[maxn<<1],V[maxn<<1],head[maxn],cnt=0;
int top[maxn],size[maxn],dis[maxn],sizee;

bool if_[maxn];

inline void in(int &now)
{
    char Cget=getchar();now=0;
    while(Cget>‘9‘||Cget<‘0‘) Cget=getchar();
    while(Cget>=‘0‘&&Cget<=‘9‘)
    {
        now=now*10+Cget-‘0‘;
        Cget=getchar();
    }
}

void pre(int now,int fa)
{
    f[now]=fa,deep[now]=deep[fa]+1;
    bel[now]=(++cnt+1)/siz,size[now]=1;
    for(int i=head[now];i;i=E[i])
    {
        if(V[i]==fa) continue;
        pre(V[i],now),size[now]+=size[V[i]];
    }
}

void dfs(int now,int chain)
{
    top[now]=chain;int pos=0;
    for(int i=head[now];i;i=E[i])
    {
        if(V[i]==f[now]) continue;
        if(size[V[i]]>size[pos]) pos=V[i];
    }
    if(pos==0) return ;
    dfs(pos,chain);
    for(int i=head[now];i;i=E[i])
    {
        if(V[i]==f[now]||V[i]==pos) continue;
        dfs(V[i],V[i]);
    }
}

int solve_lca(int x,int y)
{
    while(top[x]!=top[y])
    {
        if(deep[top[x]]<deep[top[y]]) swap(x,y);
        x=f[top[x]];
    }
    if(deep[x]>deep[y]) swap(x,y);
    return x;
}

bool cmp(QueryType aa,QueryType bb)
{
    if(bel[aa.u]==bel[bb.u]) return bel[aa.v]<bel[bb.v];
    else return bel[aa.u]<bel[bb.u];
}

inline void updata(int to)
{
    if(if_[to])
    {
        ti[num[to]]--;
        if(ti[num[to]]==0) cnt--;
    }
    else
    {
        ti[num[to]]++;
        if(ti[num[to]]==1) cnt++;
    }
    if_[to]=!if_[to];
}

int main()
{
    in(n),in(m);siz=sqrt(n);
    for(int i=1;i<=n;i++) in(num[i]),Hash[i]=num[i];
    sort(Hash+1,Hash+n+1);
    sizee=unique(Hash+1,Hash+n+1)-Hash-1;int u,v;
    for(int i=1;i<=n;i++) num[i]=lower_bound(Hash+1,Hash+sizee+1,num[i])-Hash;
    for(int i=1;i<n;i++)
    {
        in(u),in(v);
        E[++cnt]=head[u],V[cnt]=v,head[u]=cnt;
        E[++cnt]=head[v],V[cnt]=u,head[v]=cnt;
    }
    cnt=0,pre(1,0),dfs(1,1);
    for(int i=1;i<=m;i++)
    {
        in(qu[i].u),in(qu[i].v),qu[i].id=i;
        if(bel[qu[i].u]>bel[qu[i].v]) swap(qu[i].u,qu[i].v);
    }
    sort(qu+1,qu+m+1,cmp);u=1,v=1,cnt=0;
    for(int no=1;no<=m;no++)
    {
        int lca=solve_lca(u,qu[no].u);
        while(u!=f[lca]) updata(u),u=f[u];u=qu[no].u;
        while(u!=f[lca]) updata(u),u=f[u];u=qu[no].u;
        lca=solve_lca(v,qu[no].v);
        while(v!=f[lca]) updata(v),v=f[v];v=qu[no].v;
        while(v!=f[lca]) updata(v),v=f[v];v=qu[no].v;
        lca=solve_lca(u,v);
        updata(lca),ans[qu[no].id]=cnt,updata(lca);
    }
    for(int i=1;i<=m;i++) printf("%d\n",ans[i]);
    return 0;
}
时间: 2024-08-11 07:44:26

AC日记——Count on a tree II spoj的相关文章

AC日记——Count on a tree bzoj 2588

Description 给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第K小的点权.其中lastans是上一个询问的答案,初始为0,即第一个询问的u是明文. Input 第一行两个整数N,M. 第二行有N个整数,其中第i个整数表示点i的权值. 后面N-1行每行两个整数(x,y),表示点x到点y有一条边. 最后M行每行两个整数(u,v,k),表示一组询问. Output M行,表示每个询问的答案.最后一个询问不输出换行符 S

spoj COT2 - Count on a tree II

COT2 - Count on a tree II http://www.spoj.com/problems/COT2/ #tree You are given a tree with N nodes. The tree nodes are numbered from 1 to N. Each node has an integer weight. We will ask you to perform the following operation: u v : ask for how many

「SPOJ10707」Count on a tree II

「SPOJ10707」Count on a tree II 传送门 树上莫队板子题. 锻炼基础,没什么好说的. 参考代码: #include <algorithm> #include <cstdio> #include <cmath> #define rg register #define file(x) freopen(x".in", "r", stdin), freopen(x".out", "w

Count on a tree II(树上莫队)

Count on a tree II(luogu) Description 题目描述 给定一个n个节点的树,每个节点表示一个整数,问u到v的路径上有多少个不同的整数. 输入格式 第一行有两个整数n和m(n=40000,m=100000). 第二行有n个整数.第i个整数表示第i个节点表示的整数. 在接下来的n-1行中,每行包含两个整数u v,描述一条边(u,v). 在接下来的m行中,每一行包含两个整数u v,询问u到v的路径上有多少个不同的整数. 输出格式 对于每个询问,输出结果. Solutio

SPOJ COT2 Count on a tree II(树上莫队)

题目链接:http://www.spoj.com/problems/COT2/ You are given a tree with N nodes.The tree nodes are numbered from 1 to N.Each node has an integer weight. We will ask you to perfrom the following operation: u v : ask for how many different integers that repr

SPOJ COT2 Count on a tree II (树上莫队,倍增算法求LCA)

题意:给一个树图,每个点的点权(比如颜色编号),m个询问,每个询问是一个区间[a,b],图中两点之间唯一路径上有多少个不同点权(即多少种颜色).n<40000,m<100000. 思路:无意中看到树上莫队,只是拿来练练,没有想到这题的难点不在于树上莫队,而是判断LCA是否在两点之间的路径上的问题.耗时1天. 树上莫队的搞法就是: (1)DFS一次,对树进行分块,分成sqrt(n)块,每个点属于一个块.并记录每个点的DFS序. (2)将m个询问区间用所属块号作为第一关键字,DFS序作为第二关键字

BZOJ 2589 Spoj 10707 Count on a tree II 强制在线莫队算法(TLE)

题目大意:给定一棵树,每个节点有一个颜色,多次询问某条路径上颜色数量,强制在线 正解是块状数组,强制在线莫队会TLE到死,想AC这道题的不用看了 如果朴素的跑树上莫队其实并不难- - 但是强制在线 因此我们可以考虑强制在线莫队算法 将树分成O(n^1/3)块,每块大小O(n^2/3) 记录每两块之间的答案.每种颜色的出现次数和哪些点被记录到了答案中 每次查询先找到两端点所在块的端点的答案,然后暴力用莫队转移即可 空间复杂度O(n^1/3)*O(n^1/3)*O(n)=O(n^5/3) 预处理时间

SPOJ.COT2 Count on a tree II(树上莫队)

题目链接(同上一题苹果树) 为什么第10个点T了一晚上.. 下面那个却AC了?跑的也不慢. TLE: /* 在DFS序做莫队 当一个点不是另一个点的LCA时,需要加上它们LCA的贡献 */ #include <cmath> #include <cstdio> #include <cctype> #include <algorithm> #define gc() getchar() //#define gc() (SS==TT&&(TT=(SS

bzoj2589: Spoj 10707 Count on a tree II

Description 给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v),你需要回答u xor lastans和v这两个节点间有多少种不同的点权.其中lastans是上一个询问的答案,初始为0,即第一个询问的u是明文. Input 第一行两个整数N,M. 第二行有N个整数,其中第i个整数表示点i的权值. 后面N-1行每行两个整数(x,y),表示点x到点y有一条边. 最后M行每行两个整数(u,v),表示一组询问. 数据范围是N<=40000 M<=100000 点权在int范围内