zoukankan      html  css  js  c++  java
  • NOIP 2012 Day1 T3

    这道题NOIP之前没码完。。身败名裂。。

    很明显的树上倍增啦。。但有一个问题是如何快速获得每个点的两个最近和次远。。

    用set。。

    完了。。

    细节见代码。。

    // NOIP2012 Day1 T3
    
    #include <cstdio>
    #include <cstring>
    #include <vector>
    #include <set>
    #include <algorithm>
    using namespace std;
    
     typedef long long LL;
     const int N=100000+5, LOG=21, INF=0x3f3f3f3f;
    
     #define rep(i,a,b) for (int i=a; i<=b; i++)
     #define dep(i,a,b) for (int i=a; i>=b; i--)
     #define read(x) scanf("%d", &x)
     #define fill(a,x) memset(a, x, sizeof(a))
    
     struct Node {
     	int h, id;
     	bool operator < (const Node x) const { return h<x.h; }
     }c[N];
    
    
     set<Node> S;
     int n, m, s, x, x0, ans, nextt[N][2], dist[N][2], g[N][LOG];
     LL f[N][LOG][2], a, b;
    
     void update(Node x, Node y) {  // 更新树边,0为最近点,1为次近点
     	if (!nextt[x.id][0]) {
     		nextt[x.id][0]=y.id;
     		dist[x.id][0]=abs(x.h-y.h);
     	}
     	else if (abs(x.h-y.h)<dist[x.id][0] || (abs(x.h-y.h)==dist[x.id][0] && y.h<c[nextt[x.id][0]].h)) {
     		nextt[x.id][1]=nextt[x.id][0];
    		dist[x.id][1]=dist[x.id][0];
    		nextt[x.id][0]=y.id;
    		dist[x.id][0]=abs(x.h-y.h);
     	}
     	else if (!nextt[x.id][1] || abs(x.h-y.h)<dist[x.id][1] || (abs(x.h-y.h)==dist[x.id][1] && y.h<c[nextt[x.id][1]].h)) {
     		nextt[x.id][1]=y.id;
     		dist[x.id][1]=abs(x.h-y.h);
     	}
     }
     /*
      令
      g[i][j]为从i点走2^j个轮回后的位置,
      f[i][j][0]为从i点走2^j个轮回后A走过的距离,
      f[i][j][1]为从i点走2^j个轮回后B走过的距离。
     */
     void init_tree() {
     	rep(i,1,n) {
     		g[i][0]=nextt[nextt[i][1]][0];
     		f[i][0][0]=dist[i][1];
     		f[i][0][1]=dist[nextt[i][1]][0];
     	}
     	rep(j,1,20) 
     	  rep(i,1,n) {
     	  	g[i][j]=g[g[i][j-1]][j-1];
     	  	f[i][j][0]=f[i][j-1][0]+f[g[i][j-1]][j-1][0];
     	  	f[i][j][1]=f[i][j-1][1]+f[g[i][j-1]][j-1][1];
     	  }
     }
    
     void query(int s, int x, LL &da, LL &db) {  
        // 从城市s出发,最多走x距离,A、B分别开车的距离da、db
     	dep(i,20,0) if (f[s][i][0]+f[s][i][1]<=x && g[s][i]) {
     		da+=f[s][i][0];
     		db+=f[s][i][1];
     		x-=(f[s][i][0]+f[s][i][1]);
     		s=g[s][i];
     	}
     	if (nextt[s][1] && dist[s][1]<=x) da+=dist[s][1]; 
     	// 注意A可能还可以开一次
     }
    
    int main()
    {
    	read(n);
    	rep(i,1,n) {
    		read(c[i].h);
    		c[i].id=i;
    	}
    	set<Node>::iterator it;
    	dep(i,n,1) {  //  按编号从大到小顺序建树
    		S.insert(c[i]);
    		it=S.find(c[i]); 
    		// 找到c[i]的位置,并取出离它最近、次近的城市
    		if (it!=S.begin()) {
    			it--;
    			update(c[i], *it);
    			if (it!=S.begin()) {
    				it--;
    				update(c[i], *it);
    				it++;
    			}
    			it++;
    		}
    		if ((++it)!=S.end()) {
    			update(c[i], *it);
    			if ((++it)!=S.end()) update(c[i], *it);
    			it--;
    		}
    		it--;
    	}
    	init_tree();
    
    	read(x0);
    	a=1e+15, b=0;
    	rep(i,1,n) {  // 对于第一问,枚举答案
    		LL da=0, db=0;
    		query(i, x0, da, db);
    		if (db && (ans==0 || a*db>b*da)) ans=i, a=da, b=db;
    	}
    	printf("%d
    ", ans);
    
    	read(m);
    	rep(i,1,m) {
    		read(s); read(x);
    		LL da=0, db=0;
    		query(s, x, da, db);
    		printf("%I64d %I64d
    ", da, db);
    	}
    	
    	return 0;
    }
    



  • 相关阅读:
    Codeforces Round #350 (Div. 2) F. Restore a Number 模拟
    Codeforces Round #374 (Div. 2) C. Journey DP
    Codeforces Round #375 (Div. 2) D. Lakes in Berland DFS
    Intel Code Challenge Elimination Round (Div.1 + Div.2, combined) D. Generating Sets 堆
    Ubuntu 安装 搜狗输入法
    Ubuntu 搜索不到WIFI或连接不上的解决方法
    Ubuntu 线缆被拔出问题
    Codeforces Round #357 (Div. 2) D. Gifts by the List DFS
    Codeforces Round #357 (Div. 2) C. Heap Operations 优先队列
    Codeforces Round #356 (Div. 2) C. Bear and Prime 100 交互题
  • 原文地址:https://www.cnblogs.com/yearwhk/p/5119875.html
Copyright © 2011-2022 走看看