【BZOJ 1146】【CTSC 2008】网络管理network

一句话题意,树链上带改动区间第k大

感觉能够dfs+主席树O(nlog2n)过掉,但我不会写= =

于是写的线段树套平衡树+链剖+二分(改动O(nlog3n),查询O(nlog4n)慢了好多啊QAQ)

这里简介一下区间第K大做法。对于每一个线段树所”管辖“的范围,建一棵相应范围内的平衡树(我用的Treap);改动时,改动每一个包括被改动节点的线段树节点所相应的Treap。查询时。二分

答案。统计每一个区间内比当前答案小的数就可以(为了保证是序列里的数。我们能够二分答案在原序列中排名)

PS:这题真的是第K大,不是排名第K的,被坑WA了一次= =

code:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define mid (l+r)/2
#define lch i<<1,l,mid
#define rch i<<1|1,mid+1,r
using namespace std;
struct treap_node{
    treap_node *left,*right;
    int val,fix,size,wgt;
    treap_node(int val): val(val) {size=1; wgt=1; left=right=NULL; fix=rand();}
    int lsize()
      {if (left) return left->size; else return 0;}
    int rsize()
      {if (right) return right->size; else return 0;}
    void Maintain()
      {size=wgt; size+=lsize()+rsize();}
};
treap_node *seg[320001];
int f[80001],plc[80001];
int point[80001],next[200001];
struct hp{
    int u,v;
}ai[200001];
struct hq{
    int dep,fat,top,size,wson;
}tree[80001];
int n,a[80001],ans,m,totw,e=0;
void tlr(treap_node *&a)
{
    treap_node *b=a->right;
    a->right=b->left; b->left=a;
    a->Maintain(); b->Maintain(); a=b;
}
void trr(treap_node *&a)
{
    treap_node *b=a->left;
    a->left=b->right; b->right=a;
    a->Maintain(); b->Maintain(); a=b;
}
void add(int u,int v)
{
    e++; ai[e].u=u; ai[e].v=v; next[e]=point[u]; point[u]=e;
    e++; ai[e].v=u; ai[e].v=u; next[e]=point[v]; point[v]=e;
}
void insert(treap_node *&p,int value)
{
    if (!p)
      p=new treap_node(value);
    else
      {
        if (value==p->val)
          p->wgt++;
        if (value<p->val)
          {
            insert(p->left,value);
            if (p->left->fix<p->fix)
              trr(p);
          }
        if (value>p->val)
          {
            insert(p->right,value);
            if (p->right->fix<p->fix)
              tlr(p);
          }
      }
    p->Maintain();
}
void make_node(int i,int l,int r)
{
    int j;
    for (j=l;j<=r;++j)
      insert(seg[i],a[f[j]]);
}
void build(int i,int l,int r)
{
    make_node(i,l,r);
    if (l==r) return;
    build(lch); build(rch);
}
void build_tree(int now,int last,int depth)
{
    int i;
    tree[now].fat=last;
    tree[now].dep=depth;
    tree[now].size=1;
    tree[now].wson=0;
    for (i=point[now];i;i=next[i])
      if (ai[i].v!=last)
        {
          build_tree(ai[i].v,now,depth+1);
          tree[now].size+=tree[ai[i].v].size;
          if (tree[ai[i].v].size>tree[tree[now].wson].size)
            tree[now].wson=ai[i].v;
        }
}
void build_seg(int now,int tp)
{
    int i;
    tree[now].top=tp;
    plc[now]=++totw; f[totw]=now;
    if (tree[now].wson!=0)
      build_seg(tree[now].wson,tp);
    for (i=point[now];i;i=next[i])
      if (ai[i].v!=tree[now].wson&&ai[i].v!=tree[now].fat)
        build_seg(ai[i].v,ai[i].v);
}
void del(treap_node *&p,int val)
{
    if (val==p->val)
      {
        if (p->wgt==1)
          {
            if (!p->left||!p->right)
              {
                if (!p->left) p=p->right;
                else p=p->left;
              }
            else
              {
                if (p->left->fix<p->right->fix)
                  {trr(p); del(p->right,val);}
                else
                  {tlr(p); del(p->left,val);}
              }
          }
        else
          p->wgt--;
      }
    else
      {
        if (val<p->val) del(p->left,val);
        else del(p->right,val);
      }
    if (p!=NULL) p->Maintain();
}
int kth(treap_node *p,int k)
{
    if (k<=p->lsize()) return kth(p->left,k);
    if (k>p->lsize()+p->wgt) return kth(p->right,k-p->lsize()-p->wgt);
    if (k<=p->lsize()+p->wgt) return p->val;
}
int rank(treap_node *p,int val,int cur)
{
    if (val==p->val) return cur+p->lsize();
    if (val>p->val&&!p->right) return cur+p->lsize()+p->wgt;
    if (val<p->val&&!p->left) return cur;
    if (val<p->val) return rank(p->left,val,cur);
    if (val>p->val) return rank(p->right,val,cur+p->lsize()+p->wgt);
}
void query(int i,int l,int r,int x,int y,int val)
{
    if (x<=l&&y>=r)
      {
        ans+=rank(seg[i],val,0);
        return;
      }
    if (x<=mid) query(lch,x,y,val);
    if (y>mid) query(rch,x,y,val);
}
void delt(int i,int l,int r,int x,int num)
{
    if (l==x&&l==r)
      {
        del(seg[i],num);
        return;
      }
    del(seg[i],num);
    if (x<=mid) delt(lch,x,num);
    else delt(rch,x,num);
}
void ins(int i,int l,int r,int x,int num)
{
    if (l==x&&l==r)
      {
        insert(seg[i],num);
        return;
      }
    insert(seg[i],num);
    if (x<=mid) ins(lch,x,num);
    else ins(rch,x,num);
}
int Qsum(int x,int y)
{
    int t=0,f1=tree[x].top,f2=tree[y].top;
    while (f1!=f2)
      {
        //cout<<x<<‘ ‘<<y<<‘ ‘<<f1<<‘ ‘<<f2<<endl;
        if (tree[f1].dep<tree[f2].dep) {swap(x,y); swap(f1,f2);}
        t+=plc[x]-plc[f1]+1;
        x=tree[f1].fat; f1=tree[x].top;
      }
    if (tree[x].dep>tree[y].dep) swap(x,y);
    t+=plc[y]-plc[x]+1;
    return t;
}
void Q(int x,int y,int num)
{
    int f1=tree[x].top,f2=tree[y].top;
    while (f1!=f2)
      {
        if (tree[f1].dep<tree[f2].dep) {swap(x,y); swap(f1,f2);}
        query(1,1,n,plc[f1],plc[x],num);
        x=tree[f1].fat; f1=tree[x].top;
      }
    if (tree[x].dep>tree[y].dep) swap(x,y);
    query(1,1,n,plc[x],plc[y],num);
}
void work(int x,int y,int k)
{
    int l,r,t,midx,len;
    l=1; r=n;
    len=Qsum(x,y);
    if (k>len) {printf("invalid request!\n"); return;}
    k=len-k+1;
    while (l<r)
      {
        midx=(l+r+1)/2;
        t=kth(seg[1],midx);
        ans=0; Q(x,y,t);
        if (ans<=k-1) l=midx;
        else r=midx-1;
      }
    printf("%d\n",kth(seg[1],l));
}
int main()
{
    int i,x,y,k;
    scanf("%d%d",&n,&m);
    for (i=1;i<=n;++i)
      scanf("%d",&a[i]);
    for (i=1;i<n;++i)
      {
        scanf("%d%d",&x,&y);
        add(x,y);
      }
    build_tree(1,0,0);
    build_seg(1,1);
    build(1,1,n);
    for (i=1;i<=m;++i)
      {
        scanf("%d%d%d",&k,&x,&y);
        if (k==0)
          {
            delt(1,1,n,plc[x],a[x]);
            ins(1,1,n,plc[x],y);
            a[x]=y;
          }
        if (k>0)
          work(x,y,k);
      }
}
时间: 2024-10-11 11:53:44

【BZOJ 1146】【CTSC 2008】网络管理network的相关文章

BZOJ 1146 CTSC 2008 网络管理 Network 树链剖分+二分答案+平衡树

题目大意:有n个路由器,他们由n-1条边连接(形成一棵树).每一个路由器有一个延时值.有两种操作: 1.查询树上x,y两点之间的路径上第k大的权值是多少 2.修改x位置的权值为y 思路:当我大概想到怎么做这个题的时候,所想的时间复杂度已经达到了O(nlog^4n),偷偷的瞄了一眼数据范围...(N,Q<=80000,时限50s,小心翼翼的掏出计算器算了一下:8w * log(8w) ^  4 ≈ 56E,心中这样想着:Treap有常数,链剖常数大,二分不稳定的范围好像不止8w...评测机会不会很

【BZOJ 1146】 [CTSC2008]网络管理Network

1146: [CTSC2008]网络管理Network Time Limit: 50 Sec  Memory Limit: 162 MB Submit: 1938  Solved: 577 [Submit][Status] Description M公司是一个非常庞大的跨国公司,在许多国家都设有它的下属分支机构或部门.为了让分布在世界各地的N个部门之间协同工作,公司搭建了一个连接整个公司的通信网络.该网络的结构由N个路由器和N-1条高速光缆组成.每个部门都有一个专属的路由器,部门局域网内的所有机

[BZOJ 1143][CTSC 2008]祭祀river(二分图最大独立集)

题目链接:http://www.lydsy.com:808/JudgeOnline/problem.php?id=1143 这是我做的第一道CTSC的题,这题水得我都惊呆了...据说BZOJ只有第一问,没有问第二问,因为没数据,难怪这么水... 首先我们得知道二分图的独立集的概念: 二分图的独立集是二分图中一个任意两点都不相连的顶点的集合 二分图的最大独立集求法: 二分图的最大独立集=二分图点数-二分图最大匹配 然后这题就好做了.首先我们用Floyd求出相互可达的点的点对,然后用这些点对建立一个

【BZOJ】1146: [CTSC2008]网络管理Network(树链剖分+线段树套平衡树+二分 / dfs序+树状数组+主席树)

第一种做法(时间太感人): 这题我真的逗了,调了一下午,疯狂造数据,始终找不到错. 后来发现自己sb了,更新那里没有打id,直接套上u了.我.... 调了一下午啊!一下午的时光啊!本来说好中午A掉去学习第二种做法,噗 好吧,现在第一种做法是hld+seg+bst+二分,常数巨大,log^4级别,目前只会这种. 树剖后仍然用线段树维护dfs序区间,然后在每个区间建一颗平衡树,我用treap,(这题找最大啊,,,囧,并且要注意,这里的rank是比他大的数量,so,我们在二分时判断要判断一个范围,即要

BZOJ 1146: [CTSC2008]网络管理Network [树上带修改主席树]

1146: [CTSC2008]网络管理Network Time Limit: 50 Sec  Memory Limit: 162 MBSubmit: 3522  Solved: 1041[Submit][Status][Discuss] Description M公司是一个非常庞大的跨国公司,在许多国家都设有它的下属分支机构或部门.为了让分布在世界各地的N个 部门之间协同工作,公司搭建了一个连接整个公司的通信网络.该网络的结构由N个路由器和N-1条高速光缆组成. 每个部门都有一个专属的路由器,

BZOJ 1146: [CTSC2008]网络管理Network( 树链剖分 + 树状数组套主席树 )

树链剖分完就成了一道主席树裸题了, 每次树链剖分找出相应区间然后用BIT+(可持久化)权值线段树就可以完成计数. 但是空间问题很严重....在修改时不必要的就不要新建, 直接修改原来的..详见代码. 时间复杂度O(N*log^3(N)) ---------------------------------------------------------------------------- #include<cstdio> #include<cstring> #include<

BZOJ 1146: [CTSC2008]网络管理Network

1146: [CTSC2008]网络管理Network Time Limit: 50 Sec  Memory Limit: 162 MBSubmit: 3539  Solved: 1054[Submit][Status][Discuss] Description M公司是一个非常庞大的跨国公司,在许多国家都设有它的下属分支机构或部门.为了让分布在世界各地的N个 部门之间协同工作,公司搭建了一个连接整个公司的通信网络.该网络的结构由N个路由器和N-1条高速光缆组成. 每个部门都有一个专属的路由器,

【BZOJ 1148】【CTSC 2008】挂缀【BZOJ 1 148】【CTSC 2008】挂缀

[BZOJ 1 148][CTSC 2008]挂缀 这题显然是个贪心,然而我们应该如何贪才能得到最优解= =.... 假设我们按重量升序贪心,那我们可以得到反例(假设在挂缀底部):设有i,j,j<i且W_j<W_i 那么当C_i<W_j,W_i<C_j时,应该选i而不是j 假设我们按拉力升序贪心,依旧可以得到反例(假设在挂缀顶部,S为链以下重量和):设有i,j,j<i,且C_j<C_i 那么当C_i<S+W_j,S+W_i<C_j时,应该先选i当第二高的,而

Windows Server 2008 网络管理资料收集 争取做“日拱一卒“

Windows Server 2008R2系统管理[刘道军主讲MCITP课程] http://edu.51cto.com/course/course_id-510.html 安装活动目录服务器 http://edu.51cto.com/lesson/id-20503.html Windows Server 2008 R2 活动目录管理演示 http://edu.51cto.com/course/course_id-1024.html WinServer 2012文件服务器案例分析[第二十五期]