• CF 1019 题解


    A

    暴力枚举 (1) 号最后得到的票数,(geq x) 的一定都要搞掉,然后如果还是不够 (x) 的话就贪心选一下。

    B

    想了半年。。

    (b_i = a_i-a_{i+frac{n}{2}}),发现 (i o i+1)(b_i) 的变化量只能是 (0,pm 2),所以如果 (frac{n}{2}) 是奇数就一定无解。

    现在我们只要找到 (b_p = 0) 的位置就好了,我们设 (b_i eq 0),假设 (b_i > 0) ,那么 (b_{i+frac{n}{2}} < 0),类似介值定理,我们可以知道在 (i o i+frac{n}{2}) 一定有一个 (b_p=0),并且前面是一段正数,有这个性质就可以确定出来二分范围了。(b_i < 0) 反过来写即可。

    C

    神仙题。。

    首先这个图如果是 DAG 就很好做:直接隔层染色即可。

    这种 DAG 好做但是带环不好做的题可以考虑强行拆分成两个 DAG:一个只包含 (u o v,u < v) 的边,一个只包含 (u o v,u > v) 的边。

    首先我们在 (u < v) 的图上从 (1)(n) 考虑,每次如果这个点可以选,就把它后面的点标记成不能选。这样一定距离都 (leq 1)

    但是这样不满足“无边相连”的条件的原因就是若干 (u > v) 的边,所以我们从 (n)(1) 考虑这些边,如果这个点我们选了就让他连向的点不可选。设第一轮就被ban掉的点点集为 (S_0),第二轮被ban的点集为 (S_1),最后留下来的点集为 (S_2),那么一定有 (S_2)(S_1) 最大距离为 (1)(S_1)(S_0) 最大距离为 (1),所以满足最大距离为 (2)

    D

    首先这个题暴力就可以过去。。只需要在循环里别用任何运算直接预处理判断就行。

    对于这个题我们考虑先 (O(n^2)) 枚举一条底边,现在将这个底边所在的直线当做 (x) 轴,将所有的点按照在这个系下的 (y) 坐标排序,就可以二分了。

    于是我们对这些直线极角排序后去枚举这些边,但是我们发现每次还要给所有点排一下序,复杂度貌似更差了???

    其实不然,我们发现我们每次只会改变我们枚举的这条边的两个端点的相对顺序(原来枚举的是比它斜率小的,谁 (y) 坐标大谁就大,现在是枚举斜率大的,谁 (y) 坐标小谁就小)

    所以就可以 (O(n^2 log n)) 做完了。

    E

    边分治,闵科夫斯基和,凸包上二分。

    注意叉积部分会爆long long,建议使用long double算叉积。

    #include <bits/stdc++.h>
    
    #define fi first
    #define se second
    #define db double
    #define U unsigned
    #define P std::pair<int,int>
    #define LL long long
    #define pb push_back
    #define MP std::make_pair
    #define all(x) x.begin(),x.end()
    #define CLR(i,a) memset(i,a,sizeof(i))
    #define FOR(i,a,b) for(int i = a;i <= b;++i)
    #define ROF(i,a,b) for(int i = a;i >= b;--i)
    #define DEBUG(x) std::cerr << #x << '=' << x << std::endl
    
    const int MAXN = 3e5 + 5;
    
    struct Node{
    	LL x,y;
    	Node(LL x=0,LL y=0) : x(x),y(y) {}
    	
    	Node operator + (const Node &t) const {
    		return Node(x+t.x,y+t.y);
    	}
    	
    	Node operator - (const Node &t) const {
    		return Node(x-t.x,y-t.y);
    	}
    	
    	long double operator * (const Node &t) const {
    		return (long double)x*t.y-(long double)y*t.x;
    	}
    	
    	bool operator < (const Node &t) const {
    		return x == t.x ? y > t.y : x < t.x;
    	}
    };
    
    inline void build(std::vector<Node> &v){
    	std::vector<Node> t;
    	std::sort(all(v));
    	for(auto x:v){
    		while(t.size() >= 2 && (t.back()-t[(int)t.size()-2])*(x-t.back()) >= 0.0) t.pop_back();
    		t.pb(x);
    	}
    	v = t;
    }
    
    inline std::vector<Node> merge(std::vector<Node> a,std::vector<Node> b){
    	if(a.empty()) return b;
    	if(b.empty()) return a;
    	std::vector<Node> res;res.pb(a[0]+b[0]);
    	int i = 1,j = 1;
    	while(i < a.size() && j < b.size()){
    		Node v1 = a[i]-a[i-1],v2 = b[j]-b[j-1];
    		if(v1*v2 <= 0.0) res.pb(res.back()+v1),i++;
    		else res.pb(res.back()+v2),j++;
    	}
    	FOR(k,i,(int)a.size()-1) res.pb(res.back()+a[k]-a[k-1]);
    	FOR(k,j,(int)b.size()-1) res.pb(res.back()+b[k]-b[k-1]);
    	return res;
    }
    
    struct Edge{
    	int to,a,b,nxt;
    }e[MAXN<<1];
    int head[MAXN],cnt = 1;
    std::vector<std::pair<int,P> > G[MAXN];
    
    inline void add(int u,int v,int a,int b){
    	e[++cnt] = (Edge){v,a,b,head[u]};head[u] = cnt;
    	e[++cnt] = (Edge){u,a,b,head[v]};head[v] = cnt;
    }
    
    int rt;
    int mx[MAXN],sz[MAXN];
    bool vis[MAXN];
    
    inline void getroot(int v,int fa=0){
    	sz[v] = 1;
    	for(int i = head[v];i;i = e[i].nxt){
    		if(vis[i>>1] || e[i].to == fa) continue;
    		getroot(e[i].to,v);
    		sz[v] += sz[e[i].to];
    		mx[i>>1] = std::max(sz[e[i].to],mx[0]-sz[e[i].to]);
    		if(mx[i>>1] < mx[rt]) rt = i>>1;
    	}
    }
    
    LL sma[MAXN],smb[MAXN];
    std::vector<Node> S;
    
    inline void dfs(int v,int fa=0){
    	S.pb(Node(-sma[v],smb[v]));
    	for(int i = head[v];i;i = e[i].nxt){
    		if(vis[i>>1] || e[i].to == fa) continue;
    		sma[e[i].to] = smb[e[i].to] = 0;
    		sma[e[i].to] += sma[v]+e[i].a;
    		smb[e[i].to] += smb[v]+e[i].b;
    		dfs(e[i].to,v);
    	}
    }
    
    std::vector<Node> all;
    
    inline void work(int edge){
    	if(!edge) return;
    	vis[edge] = 1;
    	int u = e[edge<<1].to,v = e[edge<<1|1].to;
    	sma[u] = e[edge<<1].a;smb[u] = e[edge<<1].b;
    	sma[v] = 0;smb[v] = 0;
    	std::vector<Node> ls,rs;
    	S.clear();dfs(u);ls = S;
    	S.clear();dfs(v);rs = S;
    	build(ls);build(rs);
    	ls = merge(ls,rs);for(auto x:ls) all.pb(x);
    	// exit(0);
    	ls.clear();rs.clear();
    	rt = 0;mx[0] = sz[u];getroot(u);work(rt);
    	rt = 0;mx[0] = sz[v];getroot(v);work(rt);
    }
    
    int n,m;
    
    inline LL calc(Node v,LL x){
    	return -v.x*x+v.y;
    }
    
    inline void rebuild(int v,int fa=0){
    	int las = v,tmp = 0;
    	for(auto x:G[v]){
    		if(x.fi == fa) continue;
    		add(las,x.fi,x.se.fi,x.se.se);
    		++n;add(las,n,0,0);las = n;
    	}
    	for(auto x:G[v]){
    		if(x.fi == fa) continue;
    		rebuild(x.fi,v);
    	}
    }
    
    int main(){
    	scanf("%d%d",&n,&m);
    	if(n == 1){
    		FOR(i,1,m) printf("%d ",0);
    		puts("");return 0;
    	}
    	FOR(i,2,n){
    		int u,v,a,b;scanf("%d%d%d%d",&u,&v,&a,&b);
    		G[u].pb(MP(v,MP(a,b)));G[v].pb(MP(u,MP(a,b)));
    	}
    	rebuild(1);
    	mx[rt = 0] = n;getroot(1);
    	work(rt);
    	build(all);
    	FOR(i,0,m-1){
    		while(all.size() >= 2 && calc(all.back(),i) <= calc(all[(int)all.size()-2],i)) all.pop_back();
    		printf("%lld ",calc(all.back(),i));
    	}
    	puts("");
    	return 0;
    }
    
  • 相关阅读:
    某一字段分组取最大(小)值所在行的数据
    【JVM】01虚拟机内存模型
    POJ 1845 Sumdiv (求某个数的所有正因子的和)
    POJ 2992 Divisors (求因子个数)
    POJ 3696 The Luckiest number (欧拉函数,好题)
    POJ 1811 Prime Test (Pollard rho 大整数分解)
    POJ 2429 GCD & LCM Inverse (Pollard rho整数分解+dfs枚举)
    POJ 1305 Fermat vs. Pythagoras (毕达哥拉斯三元组)
    POJ 2142 The Balance (解不定方程,找最小值)
    POJ 1006 Biorhythms (中国剩余定理)
  • 原文地址:https://www.cnblogs.com/rainair/p/14499984.html
Copyright © 2020-2023  润新知