zoukankan      html  css  js  c++  java
  • 2021.09.13膜你赛

    2021.09.13膜你赛

    T1

    Description

    小迟生活的城市是一棵树(树指的是一个含有 \(n\) 个节点以及 \(n-1\) 条边的无向连通图),节点编号从 \(1\)\(n\),每条边拥有一个权值 \(value\),表示通过这条边的时候你需要交纳的金钱(注意,有可能这个值为负数,也就是说你经过这条边的时候你可以赚钱)

    小迟是一个杰出的马路工,他居住在节点 \(s\),他能够选择任意一个节点 \(m\),并将从节点 \(s\) 到节点 \(m\) 的简单路径(简单路径指的是不经过同一个节点两次)上的所有边的权值都修改为 \(0\).

    现在小迟获得 \(q\) 个请求,每个请求都是以 \(a \ b\) 的形式给出,表示小迟的好朋友小早希望从节点 \(a\) 走简单路径到节点 \(b\),小迟希望能最小化小早需要缴纳的钱。

    需要注意的是,小迟获得的这 \(q\) 个请求是相互独立的,也就是说您只需要对于每一个请求,决定小迟的一个修路放案,使得小早需要缴纳的钱尽可能的少。

    Solution

    树剖找最大值。

    考试的时候写的找两个点到他们 Lca 的和,让大的那个为 0,也就是输出较小边。

    考完试发现不对劲,因为可能出现这样的情况

    按照错误的写法,会把 \(lca\to v\) 的路径都变成 0,但是下图的路径变成 0 会使得花费最小。

    所以在两个路径上找 \(lca \to point\) 的最大值,取较大值,用总路径的长度减去这个大的就是最下的花费。

    Code

    由于我的怎么调都不对,所以放的 BS 的码。

    /*
      Source: road
      有负边
      a b 在 s 子树中: a b 两点到 lca 的路径中较大值 均为负值则不操作
      a b 与 s 没关系: 同上一种
      s 在 a 或 b 的子树中: 路径与 0 取 min
      s 在 a 到 b 的路径上: a 到 s 与 b 到 s 的路径中较大的与 0 取 min 
      
      可以直接把 s 当根就没这些事了
      直接考虑 a b 的 lca 即可 
      
      有点问题... 有负边 
      考虑开始消去的位置 
      首先有个暴跳的暴力
      
      把每个点到根的距离看做这个点的点权 树剖维护路径点权最大值以及最大值的点的编号 
      
      一个半小时 拍上了 
    */
    #include<cstdio>
    #include<cstring>
    #define int long long
    #define pt putchar(' ')
    #define pn putchar('\n')
    #define Abs(x) ((x) < 0 ? -(x) : (x))
    #define Max(x, y) ((x) > (y) ? (x) : (y))
    #define Min(x, y) ((x) < (y) ? (x) : (y))
    #define Swap(x, y) ((x) ^= (y) ^= (x) ^= (y))
    /*----------------------------------------------------------*/
    const int A = 1e4 + 7;
    const int B = 2e5 + 7;
    const int C = 1e6 + 7;
    const int D = 1e7 + 7;
    const int mod = 1e9 + 7;
    const int INF = 0x3f3f3f3f;
    /*----------------------------------------------------------*/
    inline void File() {
    	freopen("road.in", "r", stdin);
    	freopen("road.out", "w", stdout);
    }
    /*----------------------------------------------------------*/
    int n, q, s, fa[B], dep[B], dis[B], pos[B];
    struct edge {int v, w, nxt;} e[B << 1];
    int head[B], ecnt;
    /*----------------------------------------------------------*/
    inline int read() {
    	int x = 0, f = 1; char ch = getchar();
    	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
    	while(ch >= '0' && ch <= '9') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}
    	return x * f;
    }
    void Print(int x) {if(x < 0) putchar('-'), x = -x; if(x > 9) Print(x / 10); putchar(x % 10 ^ 48);}
    /*----------------------------------------------------------*/
    void add_edge(int u, int v, int w) {e[++ecnt] = (edge){v, w, head[u]}; head[u] = ecnt;}
    namespace Seg {
    	#define ls(x) x << 1
    	#define rs(x) x << 1 | 1
    	#define mid (t[p].l + t[p].r >> 1)
    	struct node {
    		int l, r, max, id;
    		node() {l = r = id = 0; max = -INF;}
    	} t[B << 2];
    	node operator + (node x, node y) {
    		node z; z.l = x.l; z.r = y.r;
    		if(x.max > y.max) z.max = x.max, z.id = x.id;
    		else z.max = y.max, z.id = y.id;
    		return z;
    	}
    	void build(int p, int l, int r) {
    		t[p].l = l; t[p].r = r; if(l == r) {t[p].max = dis[pos[l]]; t[p].id = pos[l]; return ;}
    		build(ls(p), l, mid); build(rs(p), mid + 1, r); t[p] = t[ls(p)] + t[rs(p)];
    	}
    	node query(int p, int l, int r) {
    		if(l <= t[p].l && t[p].r <= r) return t[p];
    		if(l <= mid) if(r > mid) return query(ls(p), l, r) + query(rs(p), l, r);
    		else return query(ls(p), l, r); else return query(rs(p), l, r);
    	}
    }
    namespace Cut {
    	int siz[B], son[B], top[B], dfn[B], kcnt;
    	void dfs1(int u, int pre) {
    		siz[u] = 1; fa[u] = pre; dep[u] = dep[pre] + 1;
    		for(int i = head[u]; i; i = e[i].nxt)
    		{
    			int v = e[i].v, w = e[i].w;
    			if(v == pre) continue;
    			dis[v] = dis[u] + w; dfs1(v, u); siz[u] += siz[v];
    			if(!son[u] || siz[son[u]] < siz[v]) son[u] = v;
    		}
    	}
    	void dfs2(int u, int tp) {
    		top[u] = tp; dfn[u] = ++kcnt; pos[kcnt] = u;
    		if(!son[u]) return ; dfs2(son[u], tp);
    		for(int i = head[u]; i; i = e[i].nxt)
    		{
    			int v = e[i].v; if(v == fa[u] || v == son[u]) continue;
    			dfs2(v, v);
    		}
    	}
    	int LCA(int x, int y) {
    		while(top[x] != top[y])
    		{
    			if(dep[top[x]] < dep[top[y]]) Swap(x, y);
    			x = fa[top[x]];
    		}
    		return dep[x] < dep[y] ? x : y;
    	}
    	int query(int x, int y) {
    		Seg::node res;
    		while(top[x] != top[y])
    		{
    			if(dep[top[x]] < dep[top[y]]) Swap(x, y);
    			res = res + Seg::query(1, dfn[top[x]], dfn[x]);
    			x = fa[top[x]];
    		}
    		if(dfn[x] > dfn[y]) Swap(x, y);
    		res = res + Seg::query(1, dfn[x], dfn[y]);
    		return res.id;
    	}
    }
    void work1() {
    	for(int i = 1; i ^ q + 1; ++i)
    	{
    		int x = read(), y = read(), z = Cut::LCA(x, y);
    		if(z == x || z == y)
    		{
    			if(dep[x] < dep[y]) Swap(x, y); int min = 0, tmp = x;
    			for(int j = x; j != fa[y]; j = fa[j])
    				if(dis[x] - dis[j] < min) min = dis[x] - dis[j], tmp = j;
    			Print(dis[x] - dis[tmp]); pn;
    		}
    		else
    		{
    			int min1 = 0, tmp1 = x, min2 = 0, tmp2 = y;
    			for(int j = x; j != fa[z]; j = fa[j])
    				if(dis[x] - dis[j] < min1) min1 = dis[x] - dis[j], tmp1 = j;
    			for(int j = y; j != fa[y]; j = fa[j])
    				if(dis[y] - dis[j] < min2) min2 = dis[y] - dis[j], tmp2 = j;
    			int res1 = dis[x] - dis[tmp1] + dis[y] - dis[z], res2 = dis[y] - dis[tmp2] + dis[x] - dis[z];
    			Print(Min(res1, res2)); pn;
    		}
    	}
    }
    void work2() {
    	for(int i = 1; i ^ q + 1; ++i)
    	{
    		int x = read(), y = read(), z = Cut::LCA(x, y);
    		if(x == y) Print(0), pn;
    		else if(z == x || z == y)
    		{
    			if(dep[x] < dep[y]) Swap(x, y);
    			int tmp = Cut::query(x, y);
    			Print(dis[x] - dis[tmp]); pn;
    		}
    		else
    		{
    			int tmp1 = Cut::query(x, z), tmp2 = Cut::query(y, z);
    			int res1 = dis[x] - dis[tmp1] + dis[y] - dis[z], res2 = dis[y] - dis[tmp2] + dis[x] - dis[z];
    			Print(Min(res1, res2)); pn;
    		}
    	}
    }
    void Main() {
    	File();
    	n = read(); q = read(); s = read();
    	for(int i = 1, x, y, z; i ^ n; ++i) x = read(), y = read(), z = read(), add_edge(x, y, z), add_edge(y, x, z);
    	Cut::dfs1(s, 0); Cut::dfs2(s, s); Seg::build(1, 1, n);
    //	if(n * q < D) work1();
    //	else work2();
    	work2();
    }
    /*----------------------------------------------------------*/
    signed main() {Main(); return 0;}
    

    T2

    Description

    随着川普的支持率逐渐下降,让川普下台的呼声越来越高,国会被迫进行了一次表决,每一位议员都有权利选择支持持川普还是反对川普,若反对的议员严格超过一半,则川普只能卸任。议员共 \(N\) 个,每个议员有两个属性:
    威望度 \(W_i\) 和忠诚度 \(H_i\)。在表决的时候,每个议员⽀持川普的概率为 \(\frac{H_i}{100}\)

    Kano 是一位腰缠万贯的企业家,出于个人原因,他想让川普下台。他拿出了 \(K\) 百万元,想要通过贿赂议员的形式来增加川普下台的可能性。每个议员每收下 1 百万元,那么他的忠诚度便会减少 \(10\),减少到 \(0\) 的时候就
    不可再减少了。

    即便这样,表决还是可能以支持的结果收场,那么 Kano 将派出刺客,暗杀所有投了支持票的议员。设所有投了支持票的议员的威望度总和为 \(S\),则成功暗杀的概率为 \(\frac{A}{A+S}\)\(A\) 为常数)。若暗杀失败,则 Kano 也将会被捕。
    现在 Kano 想知道,在最优策略下,被捕的可能性是多少?

    Solution

    考试的时候因为这 k 给谁是有方法的,然后就自闭了。

    先搜这 k 百万的分配方案,然后再搜怎么投票。

    Code

    /*
    * @Author: smyslenny
    * @Date:    2021.09.
    * @Title:   
    * @Main idea:
    */
    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cmath>
    #include <iomanip>
    #include <cstring>
    #include <cstdlib>
    #include <queue>
    #include <vector>
    
    #define ll long long
    #define INF 0x3f3f3f3f
    #define orz cout<<"LKP AK IOI\n"
    #define MAX(a,b) (a)>(b)?(a):(b)
    #define MIN(a,b) (a)>(b)?(a):(b)
    
    using namespace std;
    const int mod=998244353;
    const int M=1e3+5;
    int n,k;
    double a,cnt,Ans;
    int read()
    {
    	int x=0,y=1;
    	char c=getchar();
    	while(c<'0' || c>'9') {if(c=='-') y=0;c=getchar();}
    	while(c>='0' && c<='9') { x=x*10+(c^48);c=getchar();}
    	return y?x:-x;
    }
    struct ed{
        int w,h;
    }pep[M];
    
    void dfs_2(int js,double p,int num,int sum)
    {
    	if(js>n)
    	{
    		if(num>0) cnt+=p*a/(a+sum);
    		else cnt+=p;
    	}
    	else
    	{
    		dfs_2(js+1,p*max(0,pep[js].h)/100,num+1,sum+pep[js].w);
    		dfs_2(js+1,p*(100-max(0,pep[js].h))/100,num-1,sum);
    	}
    }
    void check()
    {
    	cnt=0;
    	dfs_2(1,1.0,0,0);
    	Ans=max(Ans,cnt);
    }
    
    void dfs(int l,int r,int K)
    {
    	check();
    	if(K==0) return;
    	for(int i=l;i<=r;i++)
    	{
    		pep[i].h-=10;
    		dfs(i,r,K-1);
    		pep[i].h+=10;
    	}
    }
    int main()
    {
    //	freopen("bride.in","r",stdin);
    //	freopen("bride.out","w",stdout);
        n=read(),k=read();scanf("%lf",&a);
        for(int i=1;i<=n;i++)
            pep[i].w=read(),pep[i].h=read();
        dfs(1,n,k);
        printf("%.6lf\n",1.0-Ans);
    }
    /*
    5 6 80
    12 90
    15 80
    22 70
    45 60
    147 50
    */
    

    T3

    Description

    其实 Kano 曾经到过由乃山,当然这名字一看山主就是 Yuno 嘛。

    当年 Kano 看见了由乃山,内心突然涌出了一股杜甫会当凌绝顶,一览众山小的豪气,于是毅然决定登山。但是 Kano 总是习惯性乱丢垃圾,增重环卫工人的负担,Yuno 并不想让 Kano 登山,于是她果断在山上设置了结界……

    Solution

    题目就是找一个被多少个不同的数经过,一个数会对当前点到根节点的路径做贡献。

    对于每一种标记 将需要打标记的点按照 \(dfs\) 序排序 依次打上加一的标记 除第一个点以外 每个点在打完加一标记之后再在自身与上一个打标记的点的 \(LCA\) 的位置打上减一标记 这样就保证了贡献不会算重

    处理完所有标记后 遍历一遍树 统计节点的权值即为该点答案

    Code

    #include<bits/stdc++.h>
    using namespace std;
    const int M=200010;
    int read()
    {
    	int x=0,y=1;
    	char c=getchar();
    	while(c<'0' || c>'9') {if(c=='-') y=0;c=getchar();}
    	while(c>='0' && c<='9') { x=x*10+(c^48);c=getchar();}
    	return y?x:-x;
    }
    struct node{
    	int g;//地点
    	int d;//编号
    }b[M];
    int f[M][20],d[M],book[M],st[M],a[M],times,v[M];
    struct ed{
    	int u,v,w,net;
    }edge[M<<1];
    int m,n,tot,t,ans;
    int x,y,z;
    queue<int> q;
    int head[M],num;
    void addedge(int u,int v)
    {
    	edge[++num].u=u;edge[num].v=v;edge[num].net=head[u];head[u]=num;
    }
    void dfs(int x)
    {//确定dfs序 
    	v[x]=1;
    	st[x]=++times;
    	for(int i=head[x];i;i=edge[i].net)
    	{
    		int y=edge[i].v;
    		if(v[y]) continue;
    		dfs(y);
    	}
    }
    void bfs()
    {//lca的预处理 
    	q.push(0);d[0]=1;
    	while(q.size()){
    		int x=q.front();q.pop();
    		for(int i=head[x];i;i=edge[i].net)
    		{
    			int y=edge[i].v;
    			if(d[y]) continue;
    			d[y]=d[x]+1;
    			f[y][0]=x;
    			for(int j=1;j<=t;++j){
    				f[y][j]=f[f[y][j-1]][j-1];
    			}
    			q.push(y);
    		}
    	}
    }
    bool cmp(node a,node b)
    {//排序 
    	if(a.d==b.d) return st[a.g]<st[b.g];
    	else return a.d<b.d;
    }
    int lca(int x,int y)
    {//lca 
    	if(d[x]>d[y]) swap(x,y);
    	for(int i=t;i>=0;--i)
    		if(d[f[y][i]]>=d[x])
    			y=f[y][i];
    	if(x==y) return x;
    	for(int i=t;i>=0;--i)
    	{
    		if(f[x][i]!=f[y][i])
    		{
    			x=f[x][i];
    			y=f[y][i];
    		}
    	}
    	return f[x][0];
    }
    void find(int x)
    {
    	v[x]=1;
    	for(int i=head[x];i;i=edge[i].net){
    		int y=edge[i].v;
    		if(v[y]) continue;
    		find(y);
    		book[x]+=book[y];
    	}
    }
    int main()
    {
    	n=read(),m=read();
    	t=((int)(log(n)/log(2)))+1;
    	for(int i=1;i<n;++i)//建边 
    		a[i]=read(),addedge(a[i],i),addedge(i,a[i]);
    	for(int i=1;i<=m;++i)
    		scanf("%d %d",&b[i].g,&b[i].d);
    	dfs(0);
    	bfs();
    	sort(b+1,b+1+m,cmp);
    	int pre=-1;
    	for(int i=1;i<=m;++i)
    	{
    		int x=b[i].g;
            book[x]++;
            if(pre!=-1) book[lca(pre,x)]--;
            pre=x;
            if(i<m&&b[i].d!=b[i+1].d)pre=-1;
    	}
    	memset(v,0,sizeof(v));
    	find(0);
    	for(int i=0;i<n;++i){
    		printf("%d\n",book[i]);
    	}
    	return 0;
    }
    
    
    
    本欲起身离红尘,奈何影子落人间。
  • 相关阅读:
    远程培训数据库迁移
    RMAN系列catalog数据库
    RMAN系列表空间恢复
    典型的一周备份脚本
    [转载]对 Oracle 备份与恢复 的补充说明转自tianlesoft的文章
    RMAN系列基于scn恢复
    使用Profile对用户Session会话进行资源限制
    RMAN系列控制文件、数据文件、redolog全部丢失
    全自动 TSPITR基于RMANLOGSEQ
    Oracle 10g EXPDP和IMPDP使用说明
  • 原文地址:https://www.cnblogs.com/jcgf/p/15319932.html
Copyright © 2011-2022 走看看