zoukankan      html  css  js  c++  java
  • [HNOI2015]开店

    题目描述

    风见幽香有一个好朋友叫八云紫,她们经常一起看星星看月亮从诗词歌赋谈到人生哲学。最近她们灵机一动,打算在幻想乡开一家小店来做生意赚点钱。

    这样的想法当然非常好啦,但是她们也发现她们面临着一个问题,那就是店开在哪里,面向什么样的人群。很神奇的是,幻想乡的地图是一个树形结构,幻想乡一共有 n个地方,编号为 1 到 n,被 n-1 条带权的边连接起来。每个地方都住着一个妖怪,其中第 i 个地方的妖怪年龄是 x_i。

    妖怪都是些比较喜欢安静的家伙,所以它们并不希望和很多妖怪相邻。所以这个树所有顶点的度数都小于或等于 3。妖怪和人一样,兴趣点随着年龄的变化自然就会变化,比如我们的 18 岁少女幽香和八云紫就比较喜欢可爱的东西。幽香通过研究发现,基本上妖怪的兴趣只跟年龄有关,所以幽香打算选择一个地方 u(u为编号),然后在 u开一家面向年龄在 L到R 之间(即年龄大于等于 L、小于等于 R)的妖怪的店。

    也有可能 u这个地方离这些妖怪比较远,于是幽香就想要知道所有年龄在 L 到 R 之间的妖怪,到点 u 的距离的和是多少(妖怪到 u 的距离是该妖怪所在地方到 u 的路径上的边的权之和) ,幽香把这个称为这个开店方案的方便值。

    幽香她们还没有决定要把店开在哪里,八云紫倒是准备了很多方案,于是幽香想要知道,对于每个方案,方便值是多少呢。

    输入输出格式

    输入格式:

    第一行三个用空格分开的数 n、Q和A,表示树的大小、开店的方案个数和妖怪的年龄上限。 第二行n个用空格分开的数 x_1、x_2、...、x_n,x_i 表示第i 个地点妖怪的年龄,满足0<=x_i<A。(年龄是可以为 0的,例如刚出生的妖怪的年龄为 0。) 接下来 n-1 行,每行三个用空格分开的数 a、b、c,表示树上的顶点 a 和 b 之间有一条权为c(1 <= c <= 1000)的边,a和b 是顶点编号。 接下来Q行,每行三个用空格分开的数 u、 a、 b。对于这 Q行的每一行,用 a、b、A计算出 L和R,表示询问”在地方 u开店,面向妖怪的年龄区间为[L,R]的方案的方便值是多少“。对于其中第 1 行,L 和 R 的计算方法为:L=min(a%A,b%A), R=max(a%A,b%A)。对于第 2到第 Q行,假设前一行得到的方便值为 ans,那么当前行的 L 和 R 计算方法为: L=min((a+ans)%A,(b+ans)%A), R=max((a+ans)%A,(b+ans)%A)。

    输出格式:

    对于每个方案,输出一行表示方便值。

    输入输出样例

    输入样例#1: 
    10 10 10
    0 0 7 2 1 4 7 7 7 9
    1 2 270
    2 3 217
    1 4 326
    2 5 361
    4 6 116
    3 7 38
    1 8 800
    6 9 210
    7 10 278
    8 9 8
    2 8 0
    9 3 1
    8 0 8
    4 2 7
    9 7 3
    4 7 0
    2 2 7
    3 2 1
    2 3 4
    输出样例#1: 复制
    1603 
    957 
    7161 
    9466 
    3232 
    5223 
    1879 
    1669 
    1282 
    0

    说明

    满足 n<=150000,Q<=200000。对于所有数据,满足 A<=10^9

    题解:

    主席树鬼题...

    我们先考虑一个简化版的问题:给你一个点,求这个点到树上所有点的距离和。

    可以发现这个点到每个点的距离都是dis[u]+dis[v]-dis[lca]*2

    考虑熟练剖分,然后将所有的怪物按年龄排序,对于每一个怪物,我们在主席树上维护它到根节点的那一段区间。

    那么对于题目所给的每一个方案,我们的答案就是 当前区间的主席树中所有边权值*经过的次数+dis[u]*sum-u到根节点的路径上的权值和*2

      1 //Never forget why you start
      2 #include<iostream>
      3 #include<cstdio>
      4 #include<cstdlib>
      5 #include<cstring>
      6 #include<cmath>
      7 #include<algorithm>
      8 #define ll(x) seg[x].l
      9 #define rr(x) seg[x].r
     10 using namespace std;
     11 typedef long long lol;
     12 int n,m,mod;
     13 struct point{
     14   int x,id;
     15   friend bool operator < (const point a,const point b){
     16     if(a.x!=b.x)return a.x<b.x;
     17     else return a.id<b.id;
     18   }
     19 }a[150005];
     20 struct node{
     21   int next,to;
     22   lol dis;
     23 }edge[300005];
     24 int head[150005],size;
     25 void putin(int from,int to,lol dis){
     26   size++;
     27   edge[size].next=head[from];
     28   edge[size].to=to;
     29   edge[size].dis=dis;
     30   head[from]=size;
     31 }
     32 int fa[150005],siz[150005],son[150005],top[150005],pos[150005],dfscnt;
     33 lol last[150005],len[150005],dis[150005];
     34 void dfs1(int r,int father){
     35   int i;
     36   siz[r]++;
     37   fa[r]=father;
     38   for(i=head[r];i!=-1;i=edge[i].next){
     39     int y=edge[i].to;
     40     if(y!=father){
     41       dis[y]=dis[r]+edge[i].dis;
     42       dfs1(y,r);
     43       siz[r]+=siz[y];
     44       if(son[r]==-1||siz[son[r]]<siz[y])son[r]=y,last[son[r]]=edge[i].dis;
     45     }
     46   }
     47 }
     48 void dfs2(int r,int tmp,lol l){
     49   int i;
     50   top[r]=tmp;
     51   pos[r]=++dfscnt;
     52   len[dfscnt]=l;
     53   if(son[r]!=-1)dfs2(son[r],tmp,last[son[r]]);
     54   for(i=head[r];i!=-1;i=edge[i].next){
     55     int y=edge[i].to;
     56     if(y!=son[r]&&y!=fa[r])
     57       dfs2(y,y,edge[i].dis);
     58   }
     59 }
     60 int root[150005],cnt,r[500005],tot;
     61 struct Seg{
     62   int l,r;
     63   lol sum,lazy;
     64 }seg[10000005];
     65 int newnode(int root){
     66   cnt++;
     67   seg[cnt]=seg[root];
     68   return cnt;
     69 }
     70 void push_up(int root,int left,int right){
     71   seg[root].sum=seg[ll(root)].sum+seg[rr(root)].sum+seg[root].lazy*(len[right]-len[left-1]);
     72 }
     73 void insert(int &root,int left,int right,int l,int r){
     74   root=newnode(root);
     75   if(l<=left&&right<=r){
     76     seg[root].lazy++;
     77     seg[root].sum+=(len[right]-len[left-1]);
     78     return;
     79   }
     80   if(l>right||r<left)return;
     81   int mid=(left+right)>>1;
     82   if(l<=mid)insert(ll(root),left,mid,l,r);
     83   if(mid<r)insert(rr(root),mid+1,right,l,r);
     84   push_up(root,left,right);
     85 }
     86 lol query(int lroot,int rroot,int left,int right,int l,int r,lol la){
     87   if(l<=left&&right<=r){return seg[rroot].sum-seg[lroot].sum+1ll*la*(len[right]-len[left-1]);}
     88   if(l>right||r<left)return 0;
     89   la+=seg[rroot].lazy-seg[lroot].lazy;
     90   int mid=(left+right)>>1;
     91   lol ans=0;
     92   if(l<=mid)ans+=query(ll(lroot),ll(rroot),left,mid,l,r,la);
     93   if(mid<r)ans+=query(rr(lroot),rr(rroot),mid+1,right,l,r,la);
     94   return ans;
     95 }
     96 int chain_insert(int x){
     97   while(x){tot++;r[tot]=r[tot-1];insert(r[tot],1,n,pos[top[x]],pos[x]);x=fa[top[x]];}
     98   return r[tot];
     99 }
    100 lol chain_query(int l,int r,int x){
    101   lol ans=0;
    102   while(x){ans+=query(root[l-1],root[r],1,n,pos[top[x]],pos[x],0);x=fa[top[x]];}
    103   return ans;
    104 }
    105 void clean(){
    106   memset(son,-1,sizeof(son));
    107   memset(head,-1,sizeof(head));
    108   size=0;
    109 }
    110 int main(){
    111   int i,j;
    112   clean();
    113   scanf("%d%d%d",&n,&m,&mod);
    114   for(i=1;i<=n;i++){
    115     scanf("%d",&a[i].x);
    116     a[i].id=i;
    117   }
    118   sort(a+1,a+n+1);
    119   for(i=1;i<n;i++){
    120     int u,v;
    121     lol s;
    122     scanf("%d%d%lld",&u,&v,&s);
    123     putin(u,v,s);
    124     putin(v,u,s);
    125   }
    126   dfs1(1,0);dfs2(1,1,0);
    127   for(i=1;i<=n;i++)len[i]+=len[i-1];
    128   for(i=1;i<=n;i++)root[i]=chain_insert(a[i].id);
    129   lol ans=0;
    130   for(i=1;i<=m;i++){
    131     lol u,x,y;
    132     scanf("%lld%lld%lld",&u,&x,&y);
    133     lol l=min((x+ans)%mod,(y+ans)%mod),r=max((x+ans)%mod,(y+ans)%mod);
    134     if(l>r)swap(l,r);
    135     l=lower_bound(a+1,a+n+1,(point){l,0})-a;r=upper_bound(a+1,a+n+1,(point){r,(int)1e9})-a-1;
    136     ans=1ll*(r-l+1)*dis[u]+query(root[l-1],root[r],1,n,1,n,0)-2ll*chain_query(l,r,u);
    137     printf("%lld
    ",ans);
    138   }
    139   return 0;
    140 }
  • 相关阅读:
    从0开始学习ssh之搭建环境
    yii2-user 一个好用的用户扩展
    yii2下使用支付宝
    SQL迅速增加表中记录语句
    浅谈Java分页技术
    浅谈JavaWEB入门必备知识之Servlet入门案例详解
    CSS控制之IE常见BUG及解决方案
    Java-Swing编程之对话框案例详解
    浅谈Java工具类CommonUtils的使用
    浅谈Log4j
  • 原文地址:https://www.cnblogs.com/huangdalaofighting/p/8256772.html
Copyright © 2011-2022 走看看