51 nod 1297 管理二叉树

原题链接:https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1297

先是暴力加优化T了最后两个点……

我还是来想想正解吧。

先写棵线段树把二叉搜索树建出来,然后在树上做下点分治就好了。

#include<cstdio>
#include<cstring>
#include<algorithm>
#define lp (p<<1)
#define rp ((p<<1)|1)
using namespace std;

int read_p,read_ca;
inline int read(){
    read_p=0;read_ca=getchar();
    while(read_ca<‘0‘||read_ca>‘9‘) read_ca=getchar();
    while(read_ca>=‘0‘&&read_ca<=‘9‘) read_p=read_p*10+read_ca-48,read_ca=getchar();
    return read_p;
}
struct na{int y,z,ne,k;}b[200001],B[4000001];
int n,m,a[200001],x,y,l[200001],num=0,de[200001],L[200001],Num=0,s[200001],Si,ro,ma;
bool bo[200001];
long long mmh[200001][5],S[200001][5];
long long MMH=0;
inline void in(int x,int y){b[++num].y=y;b[num].ne=l[x];l[x]=num;}
inline void In(int x,int y,int z,int k){B[++Num].y=y;B[Num].z=z;B[Num].k=k;B[Num].ne=L[x];L[x]=Num;}
struct tree{int ma,mi;}t[4000001];
void add(int p,int l,int r,int v){
    if (a[t[p].ma]<a[v]||t[p].ma==0) t[p].ma=v;
    if (a[t[p].mi]>a[v]||t[p].mi==0) t[p].mi=v;
    if (l==r) return;
    int mid=l+r>>1;
    if (a[v]<=mid) add(lp,l,mid,v);else add(rp,mid+1,r,v);
}
int quea(int p,int l,int r,int R){
    if (R>=r) return t[p].ma;
    int mid=l+r>>1;
    if (R<=mid) return quea(lp,l,mid,R);else if (mid=quea(rp,mid+1,r,R)) return mid;else return t[lp].ma;
}
int quei(int p,int l,int r,int R){
    if (R<=l) return t[p].mi;
    int mid=l+r>>1;
    if (R>mid) return quei(rp,mid+1,r,R);else if (mid=quei(lp,l,mid,R)) return mid;else return t[rp].mi;
}
void gs(int x,int f){
    s[x]=1;
    int u=0;
    for (register int i=l[x];i;i=b[i].ne)
    if (b[i].y!=f&&!bo[b[i].y]){
        gs(b[i].y,x);
        s[x]+=s[b[i].y];
        if (u<s[b[i].y]) u=s[b[i].y];
    }
    if (Si-s[x]>u) u=Si-s[x];
    if (u<ma) ma=u,ro=x;
}
void dfs(int x,int f,int r,int z,int k){
    s[x]=1;
    In(x,r,z,k);
    for (register int i=l[x];i;i=b[i].ne)
    if (!bo[b[i].y]&&b[i].y!=f) dfs(b[i].y,x,r,z+1,k),s[x]+=s[b[i].y];
}
void work(int x,int S){
    Si=S;ma=1e9;gs(x,0);bo[x=ro]=1;
    int u=0;
    for (register int i=l[x];i;i=b[i].ne) if (!bo[b[i].y]) dfs(b[i].y,x,x,1,++u);In(x,x,0,++u);
    for (register int i=l[x];i;i=b[i].ne) if (!bo[b[i].y]) work(b[i].y,s[b[i].y]);
}
int main(){
    register int i,j;
    n=read();a[n+1]=n+1;add(1,0,n+1,0);add(1,0,n+1,n+1);
    a[1]=read();add(1,0,n+1,1);de[1]=1;
    for (i=2;i<=n;i++){
        a[i]=read();
        x=quea(1,0,n+1,a[i]-1);y=quei(1,0,n+1,a[i]+1);
        if (de[x]>de[y]){
            in(x,i);
            in(i,x);
            de[i]=de[x]+1;
        }else{
            in(y,i);
            in(i,y);
            de[i]=de[y]+1;
        }
        add(1,0,n+1,i);
    }
    work(1,n);
    for (i=1;i<=n;i++){
        for (j=L[i];j;j=B[j].ne) MMH+=1LL*B[j].z*(S[B[j].y][0]-S[B[j].y][B[j].k])+mmh[B[j].y][0]-mmh[B[j].y][B[j].k],
        mmh[B[j].y][0]+=B[j].z,mmh[B[j].y][B[j].k]+=B[j].z,S[B[j].y][0]++,S[B[j].y][B[j].k]++;
        printf("%lld\n",MMH);
    }
}

时间: 2024-10-20 22:20:40

51 nod 1297 管理二叉树的相关文章

51nod 1297 管理二叉树

一个初始为空的二叉搜索树T,以及1到N的一个排列P: {a1, a2, ..., aN}.我们向这个二叉搜索树T添加这些数,从a1开始, 接下来是 a2, ..., 以aN结束.在每一个添加操作后,输出T上每对节点之间的距离之和. 例如:4 7 3 1 8 2 6 5.最终的二叉树为: 4 /   \ 3      7 /      /   \ 1      6     8 \    / 2  5 节点两两之间的距离和 = 6+5+5+4+3+2+1+5+4+4+3+2+1+4+3+3+2+1+

51 nod 1495 中国好区间

1495 中国好区间 基准时间限制:0.7 秒 空间限制:131072 KB 分值: 80 难度:5级算法题 阿尔法在玩一个游戏,阿尔法给出了一个长度为n的序列,他认为,一段好的区间,它的长度是>=k的,且该区间的第k大的那个数,一定大于等于T.那么问题来了,阿尔法想知道有多少好的区间. 由于阿尔法的序列长度实在是太大了,无法在规定时间内读入. 他想了一个绝妙的方法. 读入a[0],b,c,p,则a[i]=(a[i-1]*b+c)mod p. 样例解释: a1~a5分别为47,135,247,3

51 nod 1766 树上的最远点对(线段树+lca)

1766 树上的最远点对 基准时间限制:3 秒 空间限制:524288 KB 分值: 80 难度:5级算法题 n个点被n-1条边连接成了一颗树,给出a~b和c~d两个区间,表示点的标号请你求出两个区间内各选一点之间的最大距离,即你需要求出max{dis(i,j) |a<=i<=b,c<=j<=d} (PS 建议使用读入优化) Input 第一行一个数字 n n<=100000. 第二行到第n行每行三个数字描述路的情况, x,y,z (1<=x,y<=n,1<

51 nod 1439 互质对(Moblus容斥)

1439 互质对 题目来源: CodeForces 基准时间限制:2 秒 空间限制:131072 KB 分值: 160 难度:6级算法题 有n个数字,a[1],a[2],…,a[n].有一个集合,刚开始集合为空.然后有一种操作每次向集合中加入一个数字或者删除一个数字.每次操作给出一个下标x(1 ≤ x ≤ n),如果a[x]已经在集合中,那么就删除a[x],否则就加入a[x]. 问每次操作之后集合中互质的数字有多少对. 注意,集合中可以有重复的数字,两个数字不同当且仅当他们的下标不同. 比如a[

51 nod 1188 最大公约数之和 V2

1188 最大公约数之和 V2 题目来源: UVA 基准时间限制:2 秒 空间限制:262144 KB 分值: 160 难度:6级算法题 给出一个数N,输出小于等于N的所有数,两两之间的最大公约数之和. 相当于计算这段程序(程序中的gcd(i,j)表示i与j的最大公约数): G=0; for(i=1;i<N;i++) for(j=i+1;j<=N;j++) { G+=gcd(i,j); } Input 第1行:1个数T,表示后面用作输入测试的数的数量.(1 <= T <= 5000

51 nod 1055 最长等差数列(dp)

1055 最长等差数列 基准时间限制:2 秒 空间限制:262144 KB 分值: 80 难度:5级算法题 N个不同的正整数,找出由这些数组成的最长的等差数列. 例如:1 3 5 6 8 9 10 12 13 14 等差子数列包括(仅包括两项的不列举) 1 3 5 1 5 9 13 3 6 9 12 3 8 13 5 9 13 6 8 10 12 14 其中6 8 10 12 14最长,长度为5. Input 第1行:N,N为正整数的数量(3 <= N <= 10000). 第2 - N+1行

51 nod 1610 路径计数(Moblus+dp)

1610 路径计数 基准时间限制:1 秒 空间限制:131072 KB 分值: 80 难度:5级算法题 路径上所有边权的最大公约数定义为一条路径的值. 给定一个有向无环图.T次修改操作,每次修改一条边的边权,每次修改后输出有向无环图上路径的值为1的路径数量(对1,000,000,007取模). Input 第一行两个整数n和m,分别表示有向无环图上的点数和边数.(1<=n<=100,1<=m<=50,000) 第2~m+1行每行三个数x,y,z,表示有一条从x到y权值为z的边.(1

51 nod 1405 树的距离之和

1405 树的距离之和 基准时间限制:1 秒 空间限制:131072 KB 分值: 40 难度:4级算法题 给定一棵无根树,假设它有n个节点,节点编号从1到n, 求任意两点之间的距离(最短路径)之和. Input 第一行包含一个正整数n (n <= 100000),表示节点个数. 后面(n - 1)行,每行两个整数表示树的边. Output 每行一个整数,第i(i = 1,2,...n)行表示所有节点到第i个点的距离之和. Input示例 4 1 2 3 2 4 2 Output示例 5 3 5

51 nod 1427 文明 (并查集 + 树的直径)

1427 文明 题目来源: CodeForces 基准时间限制:1.5 秒 空间限制:131072 KB 分值: 160 难度:6级算法题 安德鲁在玩一个叫“文明”的游戏.大妈正在帮助他. 这个游戏里面有n个城市和m条双向的道路.城市从1到n编号.对于每一对城市,他们之间要么有唯一的一条道路,要么就是不可互达.一条道路的定义是一个包含不同城市的序列 v1, v2,...,vk ,  vi  和  vi+1 (1≤ i < k)之间有直接的一条道路相连.这条道路的长度是k-1.两个城市在同一区域的