COJ968 WZJ的数据结构(负三十二)

WZJ的数据结构(负三十二)
难度级别:D; 运行时间限制:5000ms; 运行空间限制:262144KB; 代码长度限制:2000000B

试题描述

给你一棵N个点的无根树,边上均有权值,每个点上有一盏灯,初始均亮着。请你设计一个数据结构,回答M次操作。

1 x:将节点x上的灯拉一次,即亮变灭,灭变亮。

2 x k:询问当前所有亮灯的节点中距离x第k小的距离(注意如果x亮着也算入)。


输入

第一行为一个正整数N。
第二行到第N行每行三个正整数ui,vi,wi。表示一条树边从ui到vi,距离为wi。
第N+1行为一个正整数M。
最后M行每行三个或两个正整数,格式见题面。

输出

对于每个询问操作,输出答案。

输入示例

10
1 2 2
1 3 1
1 4 3
1 5 2
4 6 2
4 7 1
6 8 1
7 9 2
7 10 1
5
2 1 4
1 5
2 1 4
2 1 9
2 1 1

输出示例

2
3
6
0

其他说明

1<=N,M<=50000
1<=x,ui,vi<=N,1<=v,wi<=1000

动态树分治的码农题啦。

对于每个节点用两棵Treap分别维护子树中亮灯的节点到其距离与子树中亮灯的节点到其父亲距离。

修改直接insert/remove。

询问先二分答案,转化成判定问题,这很容易在Treap上做。

修改O(log^2n),询问O(log^3n),常数还挺小的。

说起来还真是简单呢!写了2h+。

#include<cstdio>
#include<cctype>
#include<queue>
#include<cstring>
#include<algorithm>
#define rep(i,s,t) for(int i=s;i<=t;i++)
#define dwn(i,s,t) for(int i=s;i>=t;i--)
#define ren for(int i=first[x];i;i=next[i])
using namespace std;
inline int read() {
    int x=0,f=1;char c=getchar();
    for(;!isdigit(c);c=getchar()) if(c==‘-‘) f=-1;
    for(;isdigit(c);c=getchar()) x=x*10+c-‘0‘;
    return x*f;
}
const int maxn=100010;
struct Node {
    Node* ch[2];
    int r,s,v;
    void maintain() {s=ch[0]->s+ch[1]->s+1;}
}nodes[maxn*20],*null=&nodes[0];
int ToT;queue<Node*> Q;
Node* newnode(int v) {
    Node* o;
    if(Q.empty()) o=&nodes[++ToT];
    else o=Q.front(),Q.pop();
    o->v=v;o->s=1;o->ch[0]=o->ch[1]=null;o->r=rand();
    return o;
}
void del(Node* &o) {Q.push(o);o=null;}
void rotate(Node* &o,int d) {
    Node* k=o->ch[d^1];o->ch[d^1]=k->ch[d];k->ch[d]=o;
    o->maintain();k->maintain();o=k;
}
void insert(Node* &o,int v) {
    if(o==null) o=newnode(v);
    else {
        int d=v>o->v;insert(o->ch[d],v);
        if(o->ch[d]->r>o->r) rotate(o,d^1);
        else o->maintain();
    }
}
void remove(Node* &o,int v) {
    if(o->v==v) {
        Node* k=o;
        if(o->ch[0]==null) o=o->ch[1],del(k);
        else if(o->ch[1]==null) o=o->ch[0],del(k);
        else {
            int d=o->ch[0]->r>o->ch[1]->r;
            rotate(o,d);remove(o->ch[d],v);
        }
    }
    else remove(o->ch[v>o->v],v);
    if(o!=null) o->maintain();
}
int query(Node* &o,int v) {
    if(o==null) return 0;
    if(v>o->v) return query(o->ch[1],v)+o->ch[0]->s+1;
    return query(o->ch[0],v);
}
int n,m,first[maxn],next[maxn<<1],to[maxn<<1],dis[maxn<<1],e;
void AddEdge(int w,int v,int u) {
    dis[++e]=w;to[e]=v;next[e]=first[u];first[u]=e;
    dis[++e]=w;to[e]=u;next[e]=first[v];first[v]=e;
}
int dep[maxn],mn[maxn<<1][20],Log[maxn<<1],cnt,pos[maxn];
void dfs(int x,int fa) {
    mn[++cnt][0]=dep[x];pos[x]=cnt;
    ren if(to[i]!=fa) {
        dep[to[i]]=dep[x]+dis[i];
        dfs(to[i],x);
        mn[++cnt][0]=dep[x];
    }
}
void pre() {
    Log[0]=-1;
    rep(i,1,cnt) Log[i]=Log[i>>1]+1;
    for(int j=1;(1<<j)<=cnt;j++)
       for(int i=1;i+(1<<j)-1<=cnt;i++)
          mn[i][j]=min(mn[i][j-1],mn[i+(1<<j-1)][j-1]);
}
int dist(int x,int y) {
    int ans=dep[x]+dep[y];
    x=pos[x];y=pos[y];if(x>y) swap(x,y);
    int k=Log[y-x+1];
    return ans-2*min(mn[x][k],mn[y-(1<<k)+1][k]);
}
int f[maxn],s[maxn],vis[maxn],size,rt;
void getroot(int x,int fa) {
    s[x]=1;int maxs=0;
    ren if(to[i]!=fa&&!vis[to[i]]) {
        getroot(to[i],x);
        s[x]+=s[to[i]];
        maxs=max(maxs,s[to[i]]);
    }
    f[x]=max(size-s[x],maxs);
    if(f[x]<f[rt]) rt=x;
}
int fa[maxn];
void solve(int x,int F) {
    vis[x]=1;fa[x]=F;
    ren if(!vis[to[i]]) {
        f[0]=size=s[to[i]];getroot(to[i],rt=0);
        solve(rt,x);
    }
}
Node *root[maxn],*root2[maxn];
void turn_on(int x) {
    insert(root[x],0);
    for(int i=x;fa[i];i=fa[i]) {
        int D=dist(x,fa[i]);
        insert(root[fa[i]],D);
        insert(root2[i],D);
    }
}
void turn_off(int x) {
    remove(root[x],0);
    for(int i=x;fa[i];i=fa[i]) {
        int D=dist(x,fa[i]);
        remove(root[fa[i]],D);
        remove(root2[i],D);
    }
}
int query(int x,int v) {
    int ans=query(root[x],++v);
    for(int i=x;fa[i];i=fa[i]) {
        int D=dist(x,fa[i]);
        ans+=query(root[fa[i]],v-D)-query(root2[i],v-D);
    }
    return ans;
}
int mark[maxn];
int main() {
    n=read();
    rep(i,1,n) root[i]=root2[i]=null;
    rep(i,2,n) AddEdge(read(),read(),read());
    dfs(1,0);pre();
    f[0]=size=n;getroot(1,rt=0);
    solve(rt,0);
    rep(i,1,n) turn_on(i);
    m=read();
    while(m--) {
        if(read()==1) {
            int x=read();
            if(mark[x]) turn_on(x);
            else turn_off(x);
            mark[x]^=1;
        }
        else {
            int x=read(),k=read();
            int l=0,r=1<<30,mid;
            while(l<r) if(query(x,mid=l+r>>1)>=k) r=mid; else l=mid+1;
            printf("%d\n",l);
        }
    }
    return 0;
}

时间: 2024-08-22 23:33:35

COJ968 WZJ的数据结构(负三十二)的相关文章

数据结构(三十二)图的遍历之广度优先遍历

一.广度优先遍历算法描述 广度优先遍历(Breadth_First_Search),又称为广度优先搜索,简称BFS.图的广度优先遍历类似于树的层序遍历. BFS算法描述:从图中的某个顶点v开始,先访问该顶点,再依次访问该顶点的每一个未被访问过的邻接点w1,w2,...:然后按此顺序访问顶点w1,w2...的各个还未 被访问过的邻接点.重复上述过程,直到图中的所有顶点都被访问过为止. 以下图为例子,顶点访问序列为{A B F C I G E D H} 二.广度优先遍历算法实现 原文地址:https

COJ 0970 WZJ的数据结构(负三十)树分治

WZJ的数据结构(负三十) 难度级别:D: 运行时间限制:1000ms: 运行空间限制:262144KB: 代码长度限制:2000000B 试题描述 给你一棵N个点的无根树,点和边上均有权值.请你设计一个数据结构,回答M次操作. 1 x v:对于树上的每一个节点y,如果将x.y在树上的距离记为d,那么将y节点的权值加上d*v. 2 x:询问节点x的权值. 输入 第一行为一个正整数N.第二行到第N行每行三个正整数ui,vi,wi.表示一条树边从ui到vi,距离为wi.第N+1行为一个正整数M.最后

COJ966 WZJ的数据结构(负三十四)

WZJ的数据结构(负三十四) 难度级别:C: 运行时间限制:20000ms: 运行空间限制:262144KB: 代码长度限制:2000000B 试题描述 给一棵n个节点的树,请对于形如"u r"的Q个询问, 回答以 u 节点为中心,半径 r 以内的节点中,权值最大的节点的编号是多少.如果有多个节点,返回编号最小的. 输入 共有一组测试数据.第一行包含一个整数 n (1 ≤ n ≤ 10^5),表示节点总数.接下来的一行,包含 n 个数字,表示每个节点的权值 vi (1 ≤ vi ≤ 1

COJ970 WZJ的数据结构(负三十)

WZJ的数据结构(负三十) 难度级别:D: 运行时间限制:1000ms: 运行空间限制:262144KB: 代码长度限制:2000000B 试题描述 给你一棵N个点的无根树,点和边上均有权值.请你设计一个数据结构,回答M次操作. 1 x v:对于树上的每一个节点y,如果将x.y在树上的距离记为d,那么将y节点的权值加上d*v. 2 x:询问节点x的权值. 输入 第一行为一个正整数N.第二行到第N行每行三个正整数ui,vi,wi.表示一条树边从ui到vi,距离为wi.第N+1行为一个正整数M.最后

42. 蛤蟆的数据结构笔记之四十二图的遍历之广度优先

42. 蛤蟆的数据结构笔记之四十二图的遍历之广度优先 本篇名言:"生活真象这杯浓酒 ,不经三番五次的提炼呵 , 就不会这样一来可口 ! -- 郭小川" 继续看下广度优先的遍历,上篇我们看了深度遍历是每次一个节点的链表是走到底的. 欢迎转载,转载请标明出处:http://write.blog.csdn.net/postedit/47029275 1.  原理 首先,从图的某个顶点v0出发,访问了v0之后,依次访问与v0相邻的未被访问的顶点,然后分别从这些顶点出发,广度优先遍历,直至所有的

工作那些事(三十二)由孙悟空的两个故事谈个人与团队

故事一: 话说唐太宗为了节省开支,西天取经项目需要裁员,接到通知的唐僧骤然头大,不知如何是好. 有人说: 先把猴子开了,因为不服从管理,再把沙僧开了,因为没有主见,再把猪开了, 因为猪肉比较贵,直接杀了卖钱,再把自已开了,因为没本事去,小白龙留下,因为有后台. 但是: 猴子是不能开的,猴子是团队中的精英,也就是大牛. 小白龙是不能开的,他是唐僧的座驾,是他身份的象征. 猪也是不能开的,对团队的氛围有重要作用. 最后 只能开掉沙僧 虽然他做事很多. 重要的是四种人: 1 唐僧:钦定的项目经理,虽然

马哥学习笔记三十二——计算机及操作系统原理

缓存方式: 直接映射 N路关联 缓存策略: write through:通写 write back:回写 进程类别: 交互式进程(IO密集型) 批处理进程(CPU密集型) 实时进程(Real-time) CPU: 时间片长,优先级低IO:时间片短,优先级高 Linux优先级:priority 实时优先级: 1-99,数字越小,优先级越低 静态优先级:100-139,数据越小,优先级越高 实时优先级比静态优先级高 nice值:调整静态优先级   -20,19:100,139   0:120 ps

[原创]ActionScript3游戏中的图像编程(连载三十二)

2.2.5 投影距离的模拟 Photoshop投影样式面板的下一个属性是距离,它也存在于Flash的投影滤镜选项中.两者初始值一致,经笔者测试,两者在效果实现和数值意义方面基本一致.Flash不需要对默认参数进行更改. 下一项是扩展,乍一看,在Flash中并没有找到对应项.但仔细观察,在Photoshop投影样式的基础选项里,除了alpha以外,就只剩该属性用了百分比. [原创]ActionScript3游戏中的图像编程(连载三十二),布布扣,bubuko.com

ASP 三十二条精华代码 (1)

ASP 三十二条精华代码 (1) 2009-08-10 09:53:03  www.hackbase.com  来源:互联网 1. oncontextmenu="window.event.returnvalue=false" 将彻底屏蔽鼠标右键 <table border oncontextmenu=return(false)><td>no</table> 可用于Table 2. <body onselectstart="return