1210D.Konrad and Company Evaluation(暴力)

Konrad是大型电气设备生产商VoltModder的人际关系顾问。今天,他的任务是评估公司的幸福程度。

为VoltModder工作的n人,从1到n。每个员工在公司中赚取的金额不同-最初,第i个人每天赚取i卢布。

在接下来的q天的每一天,工资将被修改。在第i天结束时,员工vi将开始每天赚取n + i卢布,并将成为公司中收入最高的人。员工将保留他的新工资,直到再次修改为止。

有些人彼此不喜欢。这给公司带来了极大的心理危险。正式地,如果两个人a和b彼此不喜欢,并且a的收入比b多,则员工a会对此吹嘘。危险的三元组是a,b和c三名雇员的三元组,因此,一个吹牛者将向b吹牛,然后吹牛者又吹向c。如果a不喜欢b,则b不喜欢a。

每天开始时,Konrad需要评估公司中危险三元组的数量。你能帮他做吗?

//有i个人,m对关系
//第i个人初始薪水为i
//有q次操作,第i次操作会把v(i)号的薪水提升成n+i
//如果两人之间存在关系
//薪水高的会向薪水低的炫耀
//定义u v w为一个三元组,当u向v炫耀,v向w炫耀
//询问每次操作后三元组个数

//首先,每次操作之后当前点会变成目前最大的点
//那么就把它的所有入边变成出边即可
//答案就是每个点的入度*出度的和
//关键在于怎么快速维护答案
//对每个点维护一个vector g 表示入边 
//每次修改,遍历g,把入边里的点全都改成出边,修改它们的入度和出度
//时间复杂度好像是O(nsqrt(n)),证明很复杂 
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+100;
vector<int> g[maxn];
int in[maxn],out[maxn],n,m,q;
int main () {
    scanf("%d%d",&n,&m);
    for (int i=1;i<=m;i++) {
        int x,y;
        scanf("%d%d",&x,&y);
        if (x>y) swap(x,y);
        g[x].push_back(y);
        in[x]++;
        out[y]++;
    }
    long long ans=0;
    for (int i=1;i<=n;i++) ans+=1ll*in[i]*out[i];
    printf("%lld
",ans);
    scanf("%d",&q);
    while (q--) {
        int x;
        scanf("%d",&x);
        ans-=1ll*in[x]*out[x];
        for (int y:g[x]) {
            g[y].push_back(x);
            ans-=1ll*in[y]*out[y];
            in[x]--,out[y]--,out[x]++,in[y]++;
            ans+=1ll*in[y]*out[y];
        }
        g[x].clear();
        printf("%lld
",ans);
    }
}
原文地址:https://www.cnblogs.com/zhanglichen/p/14361700.html