11/10训练笔记
P7831[CCO2021] Travelling Merchant 题解
考虑出度为0的点显然不行
随后,进行一个类似于拓扑排序的过程即可
注意到需要建反图
原图也得保留
注意判-1
代码:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
#include<queue>
using namespace std;
struct edge{
int a,b,r,p,id;
edge(int a = 0,int b = 0,int r = 0,int p = 0,int id = 0):a(a),b(b),r(r),p(p),id(id){}
bool operator<(edge o) {
return r > o.r;
}
}E1[200010];
int ans[200010],vis[200010],out[200010],n,m,cnt;
vector<pair<pair<int,int>,pair<int,int> > > E[200010];
queue<int> q;
int main()
{
cin >> n >> m;
for(int i = 1;i <= m;i++) {
cin >> E1[i].a >> E1[i].b >> E1[i].r >> E1[i].p;
E1[i].id = i;
E[E1[i].b].push_back({{E1[i].a,E1[i].id},{E1[i].r,E1[i].p}});
out[E1[i].a]++;
}
for(int i = 1;i <= n;i++) {
if(!out[i]) q.push(i);
}
sort(E1 + 1,E1 + m + 1);
memset(ans,0x3f,sizeof(ans));
for(int i = 1;i <= m;i++) {
while(!q.empty()) {
int u = q.front();
q.pop();
//cout << u << " ";
for(auto j:E[u]) {
int v = j.first.first,id = j.first.second,r = j.second.first,p = j.second.second;
if(vis[id]) continue;
if(ans[u] != 0x3f3f3f3f) ans[v] = min(ans[v],max(r,ans[u] - p));
vis[id] = true;
out[v]--;
if(!out[v]) {
q.push(v);
}
//cout << v << " ";
}
}
if(!vis[E1[i].id]) {
vis[E1[i].id] = true;
ans[E1[i].a] = min(ans[E1[i].a],E1[i].r);
out[E1[i].a]--;
if(!out[E1[i].a]) q.push(E1[i].a);
}
}
for(int i = 1;i <= n;i++) {
cout << (ans[i] == 0x3f3f3f3f ? -1 : ans[i]) << " ";
}
cout << "\n";
}
P7261[COCI2009-2010#3] PATULJCI 题解
首先对每个颜色开一个vector<int>
保存其位置,随后对于一段区间\([l,r]\)和一个颜色\(c\),可以很快速的求出\([l,r]\)内\(c\)出现的次数。
然后进行随机化,每次随机一个元素并查看他的出现次数。
若随机\(t\)次,那么随机不到的概率是\(\frac{1}{2 ^ t}\),当\(t\)取50时约等于\(10 ^ {-15}\),可以认为几乎不可能。
代码:
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
const int t = 50;
int a1[300010],n,c,m,a,b;
vector<int> E[30010];
int query(int l,int r) {
for(int i = 1;i <= t;i++) {
int p = l + rand() % (r - l + 1);
int res = upper_bound(E[a1[p]].begin(),E[a1[p]].end(),r) - lower_bound(E[a1[p]].begin(),E[a1[p]].end(),l);
if(res > (r - l + 1) / 2) {
return a1[p];
}
}
return -1;
}
int main()
{
cin >> n >> c;
for(int i = 1;i <= n;i++) {
cin >> a1[i];
E[a1[i]].push_back(i);
}
for(int i = 1;i <= c;i++) {
E[i].push_back(n + 1);
}
cin >> m;
for(int i = 1;i <= m;i++) {
cin >> a >> b;
int ans = query(a,b);
if(~ans) cout << "yes" << " " << ans << "\n";
else cout << "no" << "\n";
}
}
P6706[COCI2010-2011#7] KUGLICE 题解
首先离线,删除转添加
然后并查集维护,其中如果出现环,那么把两个定位到一个虚拟节点上即可
代码:
#include<iostream>
using namespace std;
int out[300010],vis[300010],fa[300010],ans[300010],n,q,opt,x,cnt;
pair<int,int> qu[300010];
void init() {
for(int i = 1;i <= n + 1;i++) fa[i] = i;
}
int find(int x) {
return x == fa[x] ? x : fa[x] = find(fa[x]);
}
void merge(int x,int y) {
int fx = find(x),fy = find(y);
if(fx == fy) {
fa[fx] = fa[fy] = n + 1;
} else {
fa[fx] = fy;
}
}
int main()
{
cin >> n;
init();
for(int i = 1;i <= n;i++) {
cin >> out[i];
}
cin >> q;
for(int i = 1;i <= q;i++) {
cin >> opt >> x;
qu[i] = {opt,x};
if(opt == 2) {
vis[x] = 1;
}
}
for(int i = 1;i <= n;i++) {
if(!vis[i] && out[i] != 0) {
merge(i,out[i]);
}
}
for(int i = q;i >= 1;i--) {
int opt = qu[i].first,x = qu[i].second;
if(opt == 2) {
merge(x,out[x]);
} else {
int ans1 = find(x);
ans[++cnt] = ans1;
}
}
for(int i = cnt;i >= 1;i--) {
if(ans[i] == n + 1) {
cout << "CIKLUS" << "\n";
} else cout << ans[i] << "\n";
}
cout << "\n";
}