D. Vessels

http://codeforces.com/problemset/problem/371/D 

题意:给一个多层的漏斗,当一层满后会流向下一层,最后一层满后漏出;

n(<=2e5)层数,a[]每层大小,m询问次数,op=1表示添加下标为p的层k升水,op=2表示询问p层的水有多少;

思路:并查集,将满了的建边,查询就会快点;

C++:

#include<iostream>
#include<algorithm>
#include<set>
#include<vector>
#include<queue>
#include<cmath>
#include<cstring>
#include<sstream>
#include<cstdio>
#include<ctime>
#include<map>
#include<stack>
#include<string>
using namespace std;

#define sfi(i) scanf("%d",&i)
#define sfl(i) scanf("%I64d",&i)
#define pri(i) printf("%d\n",i)
#define sff(i) scanf("%lf",&i)
#define ll long long
#define mem(x,y) memset(x,y,sizeof(x))
#define INF 0x3f3f3f3f
#define eps 1e-6
#define PI acos(-1)
#define lowbit(x) ((x)&(-x))
#define fl() printf("flag\n")
ll gcd(ll a,ll b){while(b^=a^=b^=a%=b);return a;}
const ll mod=1e9+7;
const int maxn=2e6+100;

int pre[maxn];
int n;
struct A
{
    int cap;
    int val;
}a[maxn];

int Find(int x)
{
    int r=x;
    while(r!=pre[r])
    {
        r=pre[r];
    }

    int i=x;
    int j;
    while(pre[i]!=r)
    {
        j=pre[i];
        pre[i]=r;
        i=j;
    }
    return r;
}

void join(int x,int y)
{
    int jx=Find(x);
    int jy=Find(y);

    if(jx!=jy)
    {
        if(jx>jy) pre[jy]=jx;
        else pre[jx]=jy;
    }
}

void add(int p,int x)
{
    int r=Find(p);
    while(r<=n&&x>0)
    {
        if(a[r].cap>=a[r].val+x)
        {
            a[r].val+=x;
            x=0;
        }
        else
        {
            x-=(a[r].cap-a[r].val);
            a[r].val=a[r].cap;
            join(r,r+1);
        }
        r=Find(r);
    }
}
int main()
{
    sfi(n);
    for(int i=1;i<maxn;i++) pre[i]=i;//n的话连接n+1不行,会tle
    for(int i=1;i<=n;i++)
    {
        A tmp;
        sfi(tmp.cap);
        tmp.val=0;
        a[i]=tmp;
    }
    int m;
    sfi(m);
    while(m--)
    {
        int op;
        sfi(op);
        if(op==1)
        {
            int p;
            int x;
            sfi(p);
            sfi(x);
            add(p,x);
        }
        else
        {
            int p;
            sfi(p);
            printf("%d\n",a[p].val);
        }
    }
    return 0;
}

python:

虽然写了出来但tle8了,不知道怎么优化了,刚学不久;

类的类似c++数组创建搞炸我了,列表创建会是每个地址相同,每次改都全部改=-=;不定长输入也试了很多波;

总结:多尝试才是王道!

import math

maxn = 2000009
"""""
def gcd(x,y):
    if y: return gcd(y,x%y)
    return x

def P():
    isp=[True]*(maxn+10)
    pri=[]
    for i in range(2,maxn):
        if isp[i]:
            pri.append(i)
            for j in range(i*i,maxn,i):
                isp[j]=False
    return pri
"""""

class A:
    def __init__(self,x,y):
        self.cap=x
        self.val=y

cnt=1
a={}

pre=[0]*(maxn+20)##赋值0,不然无法从指定位置赋值
n=0

def Find(x):
    r=x
    while r!=pre[r]:
        r=pre[r]
    i=x
    j=0
    while pre[i]!=r:
        j=pre[i]
        pre[i]=r
        i=j
    return int(r)

def join(x,y):
    jx=Find(x)
    jy=Find(y)
    if jx!=jy:
        if jx>jy: pre[jy]=jx
        else: pre[jx]=jy

def add(p,x):
    r=Find(p)
    while r<=n and x>0:
        if a[r].cap>=a[r].val+x:
            a[r].val+=x
            x=0
        else :
            x-=(a[r].cap-a[r].val)
            a[r].val=a[r].cap
            join(r,r+1)
        r=Find(r)

n=int(input())

for i in range(1,n+9):
    pre[i]=i

k=input()
k=k.split()

for i in range(len(k)):
    a[cnt]=A(int(k[i]),0)
    cnt+=1

##for z in range(1,3):
##        print(z,a[z].cap,a[z].val,end=' ')
##        print()

m=int(input())
while m:
    m-=1
    op=input()
    op=op.split()
    for i in range(len(op)):
        op[i]=int(op[i])
    if op[0]==1:
        p=op[1]
        x=op[2]
        add(p,x)
    else:
        p=op[1]
        print(int(a[p].val))

猜你喜欢

转载自blog.csdn.net/weixin_39132605/article/details/87646475