zoukankan      html  css  js  c++  java
  • UOJ276 [清华集训2016] 汽水 【二分答案】【点分治】【树状数组】

    题目分析:

    这种乱七八糟的题目一看就是点分治,答案有单调性,所以还可以二分答案。

    我们每次二分的时候考虑答案会不会大于等于某个值,注意到系数$k$是无意义的,因为我们可以通过转化使得$k=0$。

    合并的过程相当于很多个向量,加起来后看斜率。

    注意单个向量也要判定。

    由于有了二分的答案$Ans$。判定变得简单多了,推一下。

    令$(A,C)$是从一个点到重心的一个向量,$(B,D)$是从另一个点到重心的向量。其中$A$和$B$是重心到该点的路径权值和,$C$和$D$是经过的边数。

    $-k leq frac{A+C}{B+D} leq k Rightarrow -k(B+D) leq A+C leq k(B+D)$.

    进一步的$A+kB geq -C-kD$且$A-kB leq kD-C$。虽然有四元,但是顺序相互关联,所以实际只有两元,排序后树状数组就可以解决啦。

      1 #include<bits/stdc++.h>
      2 using namespace std;
      3 
      4 typedef long long ll;
      5 
      6 const int maxn = 50100;
      7 
      8 ll k,md; int flag = 0,num,n,rnum;
      9 vector <pair<int,ll> > g[maxn];
     10 int arr[maxn],sz[maxn],imp[maxn],cnt[maxn];
     11 struct node{ll A;int B,pla;}op[maxn];
     12 
     13 int cmp(node X,node Y){
     14     return -X.A-md*X.B < -Y.A-md*Y.B;
     15 }
     16 
     17 struct Fenwick{
     18     int C[maxn];
     19     void Add(int now){
     20     while(now <= rnum){C[now] ++; now += (now&-now);}
     21     }
     22     int query(int now){
     23     int ans = 0;
     24     while(now){ans += C[now]; now -= (now&-now);}
     25     return ans;
     26     }
     27 }T1;
     28 
     29 void read(){
     30     scanf("%d%lld",&n,&k);
     31     for(int i=1;i<n;i++){
     32     int x,y;long long v; scanf("%d%d%lld",&x,&y,&v); v -= k;
     33     g[x].push_back(make_pair(y,v)); g[y].push_back(make_pair(x,v));
     34     }
     35 }
     36 
     37 void dfs1(int now,int fa,int dp){
     38     sz[now] = 1;imp[now] = 0;
     39     for(auto it : g[now]){
     40     if((arr[it.first] && arr[it.first] < dp) || fa == it.first) continue;
     41     dfs1(it.first,now,dp); sz[now] += sz[it.first];
     42     }
     43 }
     44 
     45 int dfs2(int now,int fa,int dp,int ssz){
     46     int ans = 0;
     47     for(auto it : g[now]){
     48     if((arr[it.first] && arr[it.first] < dp) || fa == it.first) continue;
     49     int data = dfs2(it.first,now,dp,ssz);
     50     if(ans==0 || imp[ans] > imp[data])ans = data;
     51     imp[now] = max(sz[it.first],imp[now]);
     52     }
     53     imp[now] = max(imp[now],ssz-sz[now]);
     54     if(ans==0 || imp[ans] > imp[now]) ans = now;
     55     return ans;
     56 }
     57 
     58 void dfs3(int now,int fa,int dp,int A,int B){
     59     for(auto it : g[now]){
     60     if(it.first == fa || (arr[it.first] && arr[it.first] < dp)) continue;
     61     op[++num] = (node){A+it.second,B+1,it.first};
     62     dfs3(it.first,now,dp,A+it.second,B+1);
     63     }
     64 }
     65 
     66 long long lisan[maxn];
     67 void solve(int dr){
     68     rnum = num;
     69     for(int i=1;i<=num;i++){lisan[i] = -op[i].A+md*op[i].B;}
     70     sort(lisan+1,lisan+num+1);rnum = unique(lisan+1,lisan+num+1)-lisan-1;
     71     for(int i=1;i<=rnum;i++) T1.C[i]=0;
     72     for(int i=num,j=1;i>=1;i--){
     73     while(j <= num && (-op[j].A-md*op[j].B < op[i].A+md*op[i].B)){
     74         T1.Add(lower_bound(lisan+1,lisan+rnum+1,-op[j].A+md*op[j].B)-lisan);
     75         j++;
     76     }
     77     int ans=j-1-T1.query(upper_bound(lisan+1,lisan+rnum+1,op[i].A-md*op[i].B)-lisan-1);
     78     if(op[i].A-md*op[i].B < -op[i].A+md*op[i].B && j > i)ans--;
     79     if(dr == 1){
     80         if(ans - cnt[op[i].pla]){flag = 1;return;}
     81     }else{cnt[op[i].pla] = ans;}
     82     }
     83 }
     84 
     85 void divide(int now,int dp,int lst,long long AA){
     86     dfs1(now,0,dp); int heavy = dfs2(now,0,dp,sz[now]);arr[heavy] = dp;
     87     for(auto it : g[heavy]){
     88     if(arr[it.first]&&arr[it.first]<dp) continue;
     89     divide(it.first,dp+1,heavy,it.second);
     90     if(flag == 1) return;
     91     }
     92     num = 0; dfs3(heavy,0,dp,0,0); sort(op+1,op+num+1,cmp);
     93     solve(1); num = 0;
     94     if(lst) {
     95     num = 0;dfs3(now,0,dp,AA,1);
     96     sort(op+1,op+num+1,cmp);
     97     for(int i=1;i<=num;i++) cnt[op[i].pla] = 0;
     98     solve(0);
     99     }
    100 }
    101 
    102 void work(){
    103     long long l = 0,r = 1e13;
    104     while(l < r){
    105     md = (l+r)/2; flag = 0;
    106     memset(arr,0,sizeof(arr));
    107     divide(1,1,0,0);
    108     if(flag) r = md; else l = md+1;
    109     }
    110     printf("%lld",l-1);
    111 }
    112 
    113 int main(){
    114     read();
    115     work();
    116     return 0;
    117 }
  • 相关阅读:
    Serialize and Deserialize Binary Tree
    sliding window substring problem汇总贴
    10. Regular Expression Matching
    《深入理解计算机系统》(CSAPP)读书笔记 —— 第七章 链接
    程序员如何写一份合格的简历?(附简历模版)
    9个提高代码运行效率的小技巧你知道几个?
    《深入理解计算机系统》(CSAPP)读书笔记 —— 第六章 存储器层次结构
    24张图7000字详解计算机中的高速缓存
    《深入理解计算机系统》(CSAPP)实验四 —— Attack Lab
    《深入理解计算机系统》(CSAPP)读书笔记 —— 第五章 优化程序性能
  • 原文地址:https://www.cnblogs.com/Menhera/p/9347630.html
Copyright © 2011-2022 走看看