spoj COT/bzoj2588 Count on a tree

这题是学主席树的时候就想写的,,,

但是当时没写(懒)

现在来填坑

= =日常调半天lca(考虑以后背板)

主席树还是蛮好写的,但是代码出现重复,不太好,导致调试的时候心里没底(虽然事实证明主席树部分没出问题)

 1 #include <cstdio>
 2 #include <algorithm>
 3 using namespace std;
 4 struct lis{    int x,id;} li[100001];
 5 struct nod{    int num,ls,rs;} t[8000001];
 6 int n,m,x,y,z,sum=0,N=0,lastans=0;
 7 int to[200001],nex[200001],list[200001];
 8 int a[100001],h[100001],fir[100001],root[100001],f[100001],pos[100001];
 9 int log[200001],near[200001],rmq[20][200001];
10 bool operator<(lis a,lis b){    return a.x<b.x;}
11 void add(int x,int y,int z){    to[z]=y;nex[z]=fir[x];fir[x]=z;}
12 inline int lca(int x,int y){    if(x>y)    swap(x,y);
13     return (h[rmq[log[y-x+1]][x]]<h[rmq[log[y-x+1]][y-near[y-x+1]+1]])?
14     rmq[log[y-x+1]][x]:rmq[log[y-x+1]][y-near[y-x+1]+1];}
15 void build(int now,int fa)
16 {
17     f[now]=fa;root[now]=++sum;
18     int com=root[fa],cha=root[now],l=1,r=n;
19     while(l<r)
20         if(a[now]>(l+r)/2)
21             l=(l+r)/2+1,t[cha]=(nod){t[com].num+1,t[com].ls,++sum},cha=sum,com=t[com].rs;
22         else
23             r=(l+r)/2,t[cha]=(nod){t[com].num+1,++sum,t[com].rs},cha=sum,com=t[com].ls;
24     list[++N]=now;pos[now]=N;t[cha]=(nod){t[com].num+1,0,0};h[now]=h[fa]+1;
25     for(int i=fir[now];i;i=nex[i])
26     if(to[i]!=fa)
27         build(to[i],now),list[++N]=now;
28 }
29 void que(int x,int y,int z)
30 {
31     int l=1,r=n,lc=lca(pos[x],pos[y]),lcc=f[lc];
32     x=root[x],y=root[y],lc=root[lc],lcc=root[lcc];
33     while(l<r)
34         if(t[t[x].ls].num+t[t[y].ls].num-t[t[lc].ls].num-t[t[lcc].ls].num<z)
35             l=(l+r)/2+1,z-=t[t[x].ls].num+t[t[y].ls].num-t[t[lc].ls].num-t[t[lcc].ls].num,
36             x=t[x].rs,y=t[y].rs,lc=t[lc].rs,lcc=t[lcc].rs;
37         else
38             r=(l+r)/2,x=t[x].ls,y=t[y].ls,lc=t[lc].ls,lcc=t[lcc].ls;
39     lastans=li[l].x;
40 }
41 int main()
42 {
43     scanf("%d%d",&n,&m);
44     for(int i=1;i<=n;i++)
45         scanf("%d",&li[i].x),li[i].id=i;
46     sort(li+1,li+n+1);
47     for(int i=1;i<=n;i++)
48         a[li[i].id]=i;
49     for(int i=1;i<n;i++)
50         scanf("%d%d",&x,&y),add(x,y,i),add(y,x,i+n);
51     build(1,0);
52     for(int i=1;i<=N;i++)
53         rmq[0][i]=list[i];
54     for(int i=1,j=0,k=1;i<=N;log[i]=j,near[i]=k,i++)
55         if(i>k*2)    j++,k*=2;
56     for(int i=1,k=2;k<=N;i++,k*=2)
57         for(int j=1;j<=N-k+1;j++)
58             rmq[i][j]=(h[rmq[i-1][j]]<h[rmq[i-1][j+k/2]])?rmq[i-1][j]:rmq[i-1][j+k/2];
59     for(int i=1;i<=m;i++)
60         scanf("%d%d%d",&x,&y,&z),que(/*lastans^*/x,y,z),printf(i<m?"%d\n":"%d",lastans);
61     return 0;
62 } //lastans^加上以后就是强在,bzoj上的题;不加就是不强在,spoj上的题

顺便吐槽:spoj上内存限制1.5G实在太6,,,

导致我乱开数组,交bzoj的时候MLE了很多发

时间: 2024-11-05 06:53:03

spoj COT/bzoj2588 Count on a tree的相关文章

【BZOJ2588】【Spoj 10628.】 Count on a tree 可持久化线段树+lca

链接: #include <stdio.h> int main() { puts("转载请注明出处[vmurder]谢谢"); puts("网址:blog.csdn.net/vmurder/article/details/45048639"); } 题解: 对于每个树上节点存一个版本的可持久化线段树,为它到根节点上所有权值的权值线段树(需要离散化). 然后对于每次询问,这条链(a,b)的线段树就是:线段树a+线段树b?线段树lca?线段树falca 然后

【BZOJ】【2588】COT(Count On a Tree)

可持久化线段树 maya……树么……转化成序列……所以就写了个树链剖分……然后每个点保存的是从它到根的可持久化线段树. 然后就像序列一样查询……注意是多个左端点和多个右端点,处理方法类似BZOJ 1901 然后rausen(Orz!!!)粗来跟我说:你直接减去lca和fa[lca]不就好啦~搞树剖还多一个log…… 我恍然大悟!然后两个都交了一下,事实证明:我链剖写的还行,LCA写的太丑……速度反而是多一个log的链剖快QAQ(另:因为边少我就偷懒没写边表,直接vector水过) 链剖: 1 /

BZOJ2588 Count on a tree

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2588 知识点: 可持久化线段树 解题思路: 先建一棵空的权值线段树,然后按照题目给出的树以任意一点为根的\(DFS\)序来更新这棵线段树.询问\((u,v,k)\)时,其实就是查询\(T[u]\)所对应的线段树加上\(T[v]\)所对应的线段树减去\(T[u and v's LCA]\)所对应的线段树再减去\(T[fa[u and v's LCA]]\),\(LCA\)就是最近公共祖先.

SPOJ:COT2 Count on a tree II

题意 给定一个n个节点的树,每个节点表示一个整数,问u到v的路径上有多少个不同的整数. n=40000,m=100000 Sol 树上莫队模板题 # include <bits/stdc++.h> # define RG register # define IL inline # define Fill(a, b) memset(a, b, sizeof(a)) using namespace std; const int _(1e5 + 5); typedef long long ll; I

bzoj2589【 Spoj 10707】 Count on a tree II

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

【BZOJ2588】Spoj 10628. Count on a tree 主席树+LCA

[BZOJ2588]Spoj 10628. Count on a tree 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),表示一组

spoj cot: Count on a tree 主席树

10628. Count on a tree Problem code: COT 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 k : ask for the kth minimum weight on the path

SPOJ 10628 Count on a tree(Tarjan离线LCA+主席树求树上第K小)

COT - Count on a tree #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 k : ask for the kth minimum weight on the path from node u 

SPOJ Count on a tree

Count on a tree Time Limit:129MS     Memory Limit:1572864KB     64bit IO Format:%lld & %llu Submit Status Practice SPOJ COT Description 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