有用的题型!
The 2021 ICPC Asia Shanghai Regional Programming Contest
https://codeforces.com/gym/103446/problem/H
//kruskal重构树!
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5+9;
typedef long long ll;
int n,m,q,node;
int w[N],p[N],fa[N][22],deep[N];
ll sum[N],maxNum[N][22];
vector<int> to[N];
struct E {
int a,b,c;
bool operator < (const E &O) const {
return c < O.c;
}
}e[N];
int find(int x) {
if(x != p[x]) return p[x] = find(p[x]);
return x;
}
void Merge(int x,int y,int z) {
int px = find(x),py = find(y),pz = find(z);
p[px] = pz;
p[py] = pz;
}
void dfs(int u,int father) {
if(u <= n) sum[u] = w[u];
deep[u] = deep[father] + 1; //预处理倍增及sum的值!
for(int i=1; (1 << i) <= deep[u]; i++) {
fa[u][i] = fa[fa[u][i-1]][i-1];
}
for(auto v : to[u]) {
if(v == father) continue;
fa[v][0] = u;
dfs(v,u);
sum[u] += sum[v];
}
}
void dfs2(int u,int father) {
maxNum[u][0] = w[fa[u][0]] - sum[u]; //预处理u开始的2的i次幂的maxNum,maxNum为最大的障碍!
for(int i=1; (1 << i) <= deep[u]; i++) {
maxNum[u][i] = max(maxNum[u][i - 1], maxNum[fa[u][i - 1]][i - 1]);
}
for(auto v : to[u]) {
if(v == father) continue;
dfs2(v,u);
}
}
ll query(int x,int k) {
for(int i = 19; i >= 0; --i)
if(fa[x][i] && maxNum[x][i] <= k)
x = fa[x][i];
return sum[x] + k;
}
int main() {
cin >> n >> m >> q;
for(int i=1; i<=n; i++) scanf("%d",&w[i]);
for(int i=1; i<N; i++) p[i] = i;
for(int i=1; i<=m; i++) scanf("%d%d%d",&e[i].a,&e[i].b,&e[i].c);
sort(e+1,e+m+1);
node = n;
for(int i=1; i<=m; i++) {
int a = e[i].a,b = e[i].b,c = e[i].c;
int px = find(a),py = find(b);
if(px != py) {
node++;
w[node] = c;
to[node].push_back(px);
to[px].push_back(node);
to[py].push_back(node);
to[node].push_back(py);
Merge(px,py,node);
}
}
dfs(node,0);
dfs2(node,0);
while(q--) {
int x,k;
scanf("%d%d",&x,&k);
printf("%lld\n",query(x,k));
}
return 0;
}
2019 China Collegiate Programming Contest Qinhuangdao Onsite
https://codeforces.com/gym/102361/problem/F
DFS有向图找环
#include <iostream>
#include <vector>
using namespace std;
const int N = 2e6 + 9;
typedef long long ll;
vector<int> to[N];
const int MOD = 998244353;
int vis[N];
int n, m;
int Size[N], tot, h[N];
void dfs(int u, int father)
{
vis[u] = 1;
h[u] = h[father] + 1;
for (auto v : to[u])
{
if (!vis[v])
dfs(v, u);
else if (vis[v] == 1 && v != father)
{
Size[++tot] = h[u] - h[v] + 1;
}
}
vis[u] = 2;
}
ll fpow(ll a, ll b, ll c)
{
ll ans = 1;
b %= c;
while (b)
{
if (b & 1)
ans = ans * a % c;
a = a * a % c;
b >>= 1;
}
return ans;
}
int main()
{
cin >> n >> m;
for (int i = 1; i <= m; i++)
{
int a, b;
scanf("%d%d", &a, &b);
to[a].push_back(b);
to[b].push_back(a);
}
for (int i = 1; i <= n; i++)
{
if (!vis[i])
dfs(i, 0);
}
ll ans = 1;
for (int i = 1; i <= tot; i++)
{
ans = ans * (fpow(2, Size[i], MOD) - 1) % MOD;
m -= Size[i];
}
ans = ans * fpow(2, m, MOD) % MOD;
cout << ans << endl;
return 0;
}
2019 China Collegiate Programming Contest Qinhuangdao Onsite
https://codeforces.com/gym/103409/problem/E
#include <bits/stdc++.h>
using namespace std;
const int N = 1e4+9;
typedef pair<int,int> PII;
typedef long long ll;
int n,m,c;
int head[N],numE,dist[N];
bool st[N];
struct E {
int next,to,w;
}e[N];
void add(int a,int b,int c) {
e[numE] = {head[a],b,c};
head[a] = numE++;
}
bool Dijkstra(int start) {
priority_queue<PII,vector<PII>,greater<PII>> qu;
for(int i=1; i<=n; i++) dist[i] = 0x3f3f3f3f,st[i] = false;
dist[start] = 0;
qu.push({0,start});
while(!qu.empty()) {
auto t = qu.top();
qu.pop();
int ver = t.second;
if(st[ver]) continue;
st[ver] = true;
for(int i=head[ver]; ~i; i=e[i].next) {
int v = e[i].to;
if(v == start && dist[ver] + e[i].w <= c) return true;
if(dist[v] > dist[ver] + e[i].w) {
dist[v] = dist[ver] + e[i].w;
qu.push({dist[v],v});
}
}
}
return false;
}
int main() {
memset(head,-1,sizeof head);
cin >> n >> m >> c;
int minn = 2e9;
for(int i=1; i<=m; i++) {
int a,b,c;
cin >> a >> b >> c;
add(a,b,c);
minn = min(minn,c);
}
if(c < minn) puts("0");
else {
int ans = 1;
for(int i=1; i<=n; i++) {
if(Dijkstra(i)) ans = 2;
}
cout<<ans<<endl;
}
return 0;
}
P1525 [NOIP2010 提高组] 关押罪犯
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5+9;
int n,m;
int p[N],vis[N];
struct E {
int a,b,c;
bool operator < (const E &O) const {
return c > O.c;
}
}e[N];
int find(int x) {
if(x != p[x]) return p[x] = find(p[x]);
return x;
}
void Merge(int x,int y) {
int px = find(x),py = find(y);
if(px != py) p[px] = py;
}
int main() {
cin >> n >> m;
for(int i=0; i<=n; i++) p[i] = i;
for(int i=1; i<=m; i++) {
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
e[i] = {a,b,c};
}
sort(e+1,e+m+1);
int ans = 0;
for(int i=1; i<=m; i++) {
int a = e[i].a,b = e[i].b,c = e[i].c;
int px = find(a),py = find(b);
if(px == py) {
ans = c;
break;
} else {
if(!vis[a]) vis[a] = b;
else {
Merge(vis[a],b);
}
if(!vis[b]) vis[b] = a;
else {
Merge(vis[b],a);
}
}
}
cout<<ans<<endl;
return 0;
}
逆十字代码%%%%!
https://ac.nowcoder.com/acm/contest/24577/M
#include<bits/stdc++.h>
using namespace std;
const int N = 5005;
int nd,ans;
int n,m;
struct node {
map<string,int> mp;
int s0,s1;
void clear() {
s0 = 0,s1 = 0;
mp.clear();
}
int get_id(string s) {
if(mp.count(s)) return mp[s];
return mp[s] = ++nd;
}
}t[N];
void insert(int v) {
int p = 1;
char ss[N];
string s = "";
scanf("%s",ss+1);
for(int i=1; ss[i]; i++) {
if(ss[i] != '/') s += ss[i];
else {
p = t[p].get_id(s);
s = "";
}
}
p = t[p].get_id(s);
v == 1 ? t[p].s1++:t[p].s0++;
}
void dfs(int u) {
for(auto v : t[u].mp) {
int x = v.second;
dfs(x);
t[u].s1 += t[x].s1;
t[u].s0 += t[x].s0;
}
if(u == 1) return;
if(t[u].s1 && !t[u].s0) {
ans++;
for(auto v : t[u].mp) {
--ans;
}
}
}
int main() {
int _;
cin >> _;
while(_--) {
for(;nd;--nd) t[nd].clear();
nd = 1;
ans = 0;
scanf("%d%d",&n,&m);
for(int i=1; i<=n; i++) insert(1);
for(int i=1; i<=m; i++) insert(0);
dfs(1);
cout<<ans<<"\n";
}
return 0;
}
//https://codeforces.com/gym/102900/problem/D
#include <iostream>
using namespace std;
typedef long double LD;
int main()
{
int _;
scanf("%d", &_);
while (_--)
{
LD n, p1, v1, p2, v2;
scanf("%LF%LF%LF%LF%LF", &n, &p1, &v1, &p2, &v2);
if (p1 > p2) //保证第一个人再前面!
{
swap(p1, p2);
swap(v1, v2);
}
LD ans = 0;
ans = min((n + min(p1, n - p1)) / v1, (n + min(p2, n - p2)) / v2); //较快的那个自己跑完全程的人的时间!
ans = min(ans, max((n - p1) / v1, p2 / v2)); //两个各自到对面的终点的最大值!
LD l = p1, r = p2; // 应该既可以二分也可以三分mid! 左边那个人跑完(0 ~ mid),右边跑完(mid,n);
while (r - l >= 1e-10)
{
LD mid = (l + r) / 2;
LD t1 = (p1 + (mid - p1) * 2) / v1;
t1 = min(t1, (2 * p1 + mid - p1) / v1);
LD t2 = (2 * (p2 - mid) + n - p2) / v2;
t2 = min(t2, ((n - p2) * 2 + p2 - mid) / v2);
ans = min(ans, max(t1, t2));
if (t1 > t2) //如果左边人花费的时间长,那就让他少跑一段距离,所有r = mid!
r = mid;
else
l = mid;
}
printf("%.10LF\n", ans);
}
return 0;
}
//三分版本!
#include <iostream>
using namespace std;
typedef long double LD;
int main()
{
int _;
scanf("%d", &_);
while (_--)
{
LD n, p1, v1, p2, v2;
scanf("%LF%LF%LF%LF%LF", &n, &p1, &v1, &p2, &v2);
if (p1 > p2) //保证第一个人再前面!
{
swap(p1, p2);
swap(v1, v2);
}
LD ans = 0;
ans = min((n + min(p1, n - p1)) / v1, (n + min(p2, n - p2)) / v2); //较快的那个自己跑完全程的人的时间!
ans = min(ans, max((n - p1) / v1, p2 / v2)); //两个各自到对面的终点的最大值!
LD l = p1, r = p2; // 应该既可以二分也可以三分mid! 左边那个人跑完(0 ~ mid),右边跑完(mid,n);
while (r - l >= 1e-10)
{
LD lmid = l + (r - l) / 3,rmid = r - (r - l) / 3;
LD ltime,rtime;
LD t1 = (p1 + (lmid - p1) * 2) / v1;
t1 = min(t1, (2 * p1 + lmid - p1) / v1);
LD t2 = (2 * (p2 - lmid) + n - p2) / v2;
t2 = min(t2, ((n - p2) * 2 + p2 - lmid) / v2);
ltime = max(t1,t2);
/*************************/
t1 = (p1 + (rmid - p1) * 2) / v1;
t1 = min(t1, (2 * p1 + rmid - p1) / v1);
t2 = (2 * (p2 - rmid) + n - p2) / v2;
t2 = min(t2, ((n - p2) * 2 + p2 - rmid) / v2);
rtime = max(t1,t2);
ans = min(ans,min(ltime,rtime));
if(ltime > rtime) l = lmid;
else r = rmid;
}
printf("%.10LF\n", ans);
}
return 0;
}
https://codeforces.com/gym/104059/problem/C
考察STL二分!
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
const int N = 1e6+9;
typedef long long ll;
typedef pair<int,int> PII;
unordered_map<int,int> mp;
set<int> st;
int a[N];
int main() {
int n,q;
cin >> n >> q;
for(int Case=1; Case<=q; Case++) {
char s[2];
scanf("%s",s);
if(s[0] == '+') {
int a;
scanf("%d",&a);
st.erase(a);
} else if(s[0] == '-') {
int a;
scanf("%d",&a);
st.insert(a);
} else {
int a,b;
scanf("%d%d",&a,&b);
if(a > b) swap(a,b);
bool ok = true;
if(st.size() > 0) {
if(st.count(a) || st.count(b)) ok = false;
else if(*st.begin() < a) {
auto p = st.upper_bound(a);
if(p != st.end() && *p < b) ok = false;
}
else if(*st.begin() > a && *st.begin() < b) {
auto p = st.upper_bound(b);
if(p != st.end() && *p > b) ok = false;
}
}
if(!ok) cout<<"impossible\n";
else cout<<"possible\n";
}
}
return 0;
}
https://codeforces.com/contest/1760/problem/D
//双指针当然也可以unique函数去重!
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e6+9;
int a[N];
int n;
bool check(int l,int r) {
if(l > 1 && r < n) {
if(a[l-1] > a[l] && a[r] < a[r+1]) return true;
return false;
} else {
if(l == 1 && r == n) return true;
else if(l == 1) {
if(a[r] < a[r+1]) return true;
return false;
} else {
if(a[l-1] > a[l]) return true;
return false;
}
}
}
int main() {
int _;
scanf("%d",&_);
while(_--) {
scanf("%d",&n);
for(int i=1; i<=n; i++) scanf("%d",&a[i]);
int cnt = 0;
for(int i=1; i<=n; i++) {
int j = i;
while(j <= n && a[j] == a[i]) j++; //j出来后是不满足条件的第一个!
if(check(i,j-1)) {
cnt++;
}
i = j-1; //i在此之后还得自增;
}
if(cnt == 1) puts("YES");
else puts("NO");
}
return 0;
}