赛前口胡题合集(luogu紫色图论)
临近比赛 写题也写不了多少了 不如来口胡一下题
嘴上过了就试过了
P4042 [AHOI2014/JSOI2014]骑士游戏
一开始就想到全部扔进队列之后SPFA玄学松弛,觉得会T想了半天别的做法,一看题解竟然就是SPFA,觉得可以练手结果写了写发现暴力又好写,如果不开O²甚至需要加register才能过
#include <map> #include <set> #include <ctime> #include <cmath> #include <queue> #include <stack> #include <vector> #include <string> #include <bitset> #include <cstdio> #include <cstdlib> #include <cstring> #include <sstream> #include <iostream> #include <algorithm> #include <functional> using namespace std; #define For(i, x, y) for(int i=x;i<=y;i++) #define _For(i, x, y) for(int i=x;i>=y;i--) #define Mem(f, x) memset(f,x,sizeof(f)) #define Sca(x) scanf("%d", &x) #define Sca2(x,y) scanf("%d%d",&x,&y) #define Sca3(x,y,z) scanf("%d%d%d",&x,&y,&z) #define Scl(x) scanf("%lld",&x) #define Pri(x) printf("%d\n", x) #define Prl(x) printf("%lld\n",x) #define CLR(u) for(int i=0;i<=N;i++)u[i].clear(); #define LL long long #define ULL unsigned long long #define mp make_pair #define PII pair<int,int> #define PIL pair<int,long long> #define PLL pair<long long,long long> #define pb push_back #define fi first #define se second typedef vector<int> VI; LL read(){LL x = 0,f = 1;char c = getchar();while (c<'0' || c>'9'){if (c == '-') f = -1;c = getchar();} while (c >= '0'&&c <= '9'){x = x * 10 + c - '0';c = getchar();}return x*f;} const double PI = acos(-1.0); const double eps = 1e-9; const int maxn = 2e5 + 10; const int INF = 0x3f3f3f3f; const int mod = 1e9 + 7; int N,M,K; vector<int>P[maxn],Q[maxn]; LL a[maxn],b[maxn]; LL dp[maxn]; bool vis[maxn]; inline void SPFA(){ queue<int>Qu; for(int i = 1; i <= N ; i ++){ vis[i] = 1; Qu.push(i); } while(!Qu.empty()){ int u = Qu.front(); Qu.pop(); vis[u] = 0; LL sum = a[u]; for(register int i = 0; i < P[u].size(); i ++){ int v = P[u][i]; sum += dp[v]; } if(sum >= dp[u]) continue; dp[u] = sum; for(register int i = 0 ; i < Q[u].size(); i ++){ int v = Q[u][i]; if(!vis[v]){ Qu.push(v); vis[v] = 1; } } } } int main(){ Sca(N); for(int i = 1; i <= N ; i ++){ a[i] = read(); dp[i] = read(); int K = read(); while(K--){ int x = read(); P[i].pb(x); Q[x].pb(i); } } SPFA(); Prl(dp[1]); return 0; }
P2189 小Z的传感器
初看以为是一道很有操作的题,仔细一看q的范围只有5
那么每次询问先将所有没有传感器的房间用并查集连起来,然后依次每个点询问能否有一条边和初始点的并查集相连即可,时间复杂度O(Mq)
P2416 泡芙
没有口胡出来 看了题解
将整个图用tarjan边双缩点然后求树链和是否 >= 1即可
求树链和的操作可以统计前缀和(点到跟的和),然后sum(u) + sum(v) - 2 * sum(lca(u,v)) + val(lca(u,v))的做法
#include <map> #include <set> #include <ctime> #include <cmath> #include <queue> #include <stack> #include <vector> #include <string> #include <bitset> #include <cstdio> #include <cstdlib> #include <cstring> #include <sstream> #include <iostream> #include <algorithm> #include <functional> using namespace std; #define For(i, x, y) for(int i=x;i<=y;i++) #define _For(i, x, y) for(int i=x;i>=y;i--) #define Mem(f, x) memset(f,x,sizeof(f)) #define Sca(x) scanf("%d", &x) #define Sca2(x,y) scanf("%d%d",&x,&y) #define Sca3(x,y,z) scanf("%d%d%d",&x,&y,&z) #define Scl(x) scanf("%lld",&x) #define Pri(x) printf("%d\n", x) #define Prl(x) printf("%lld\n",x) #define CLR(u) for(int i=0;i<=N;i++)u[i].clear(); #define LL long long #define ULL unsigned long long #define mp make_pair #define PII pair<int,int> #define PIL pair<int,long long> #define PLL pair<long long,long long> #define pb push_back #define fi first #define se second typedef vector<int> VI; int read(){int x = 0,f = 1;char c = getchar();while (c<'0' || c>'9'){if (c == '-') f = -1;c = getchar();} while (c >= '0'&&c <= '9'){x = x * 10 + c - '0';c = getchar();}return x*f;} const double PI = acos(-1.0); const double eps = 1e-9; const int maxn = 3e5 + 10; const int INF = 0x3f3f3f3f; const int mod = 1e9 + 7; int N,M,K; struct Edge{ int to,next,dis; bool cut; }edge[maxn * 2]; int head[maxn],tot; void init(){ for(int i = 0 ; i <= N; i ++) head[i] = -1; tot = 0; } void add(int u,int v,int w){ edge[tot].to = v; edge[tot].next = head[u]; edge[tot].dis = w; edge[tot].cut = 0; head[u] = tot++; } int val[maxn],Low[maxn],dfn[maxn],Stack[maxn],belong[maxn]; int Index,top,scc; bool Instack[maxn]; void Tarjan(int u,int la){ int v; Low[u] = dfn[u] = ++Index; Stack[top++] = u; Instack[u] = true; for(int i = head[u]; ~i; i = edge[i].next){ int v = edge[i].to; if(v == la) continue; if(!dfn[v]){ Tarjan(v,u); Low[u] = min(Low[u],Low[v]); if(Low[v] > dfn[u]){ edge[i].cut = edge[i ^ 1].cut = 1; } }else if(Instack[v] && Low[u] > dfn[v]) Low[u] = dfn[v]; } if(Low[u] == dfn[u]){ scc++; do{ v = Stack[--top]; Instack[v] = false; belong[v] = scc; }while(v != u); } } struct node{ int to,dis; node(int to = 0,int dis = 0):to(to),dis(dis){} }; vector<node>MAP[maxn]; const int SP = 20; int pa[maxn][SP],dep[maxn]; int pre[maxn]; void DFS(int u,int fa,int sum){ pa[u][0] = fa; dep[u] = dep[fa] + 1; sum += val[u]; pre[u] = sum; for(int i = 1; i < SP; i ++) pa[u][i] = pa[pa[u][i - 1]][i - 1]; for(int i = 0; i < MAP[u].size(); i++){ node v = MAP[u][i]; if(v.to == fa) continue; DFS(v.to,u,sum + v.dis); } } int lca(int u,int v){ if(dep[u] < dep[v]) swap(u,v); int t = dep[u] - dep[v]; for(int i = 0; i < SP; i ++) if(t & (1 << i)) u = pa[u][i]; for(int i = SP - 1; i >= 0; i --){ int uu = pa[u][i],vv = pa[v][i]; if(uu != vv){ u = uu; v = vv; } } return u == v?u:pa[u][0]; } int main(){ Sca2(N,M); init(); for(int i = 1; i <= M ; i ++){ int u = read(),v = read(),w = read(); add(u,v,w); add(v,u,w); } for(int i = 1; i <= N ; i ++) if(!dfn[i]) Tarjan(i,i); for(int i = 1; i <= N ; i ++){ for(int j = head[i]; ~j; j = edge[j].next){ int v = edge[j].to; if(belong[v] == belong[i]){ if(edge[j].dis) val[belong[i]] = 1; continue; } if(edge[j].cut){ MAP[belong[i]].pb(node(belong[v],edge[j].dis)); } } } DFS(1,0,0); K = read(); while(K--){ int u = belong[read()],v = belong[read()]; int l = lca(u,v); if(pre[u] + pre[v] - 2 * pre[l] + val[l] > 0) puts("YES"); else puts("NO"); } return 0; }
P1264 K-联赛
数据量太小了 很容易想到网络流去搞
枚举每个队胜利的情况,如果某个队可以成为冠军,那么他的场次全胜可以算出其他队伍最多胜的场次。
去掉其他队伍已经胜利的场次,留下来的就是再接下来的比赛中最多胜利的场次,即至少失败的场次,每场比赛作为一个结点允许两个队中的一个队失败,最大流判断是否最终失败的总次数等于每个队伍至少失败的场次之和即可
P2175 小Z的游戏分队
(口胡了一个错误的解法,看了题解才发现)
先建一个反图然后图上染色判断可行性,然后每个连通块有一个一个阵营的人数a和一个阵营的人数b,做一个01背包判断一个阵营能出现人数的数量即可
P5001 魔法祝福
感觉是个裸的最短路?
维护每个点 每个诅咒数量下的最短时间 树状数组维护个前缀最小值,SPFA松弛就可以了
update:题解竟然是直接维护一个三元组去暴力更新SPFA 在1e6的数据下竟然能拿满分,过于玄学
P4151 [WC2011]最大XOR和路径
找出所有环 将环上的异或和丢入线性基,随便挑一条1-N的链上的异或和作为初始值求异或最大和
P2783 有机化学之神偶尔会做作弊
tarjan缩点然后LCA
P1300 城市街道交通费系统
感觉只是一道存路径 + 朝向的裸最短路
P1344 [USACO4.4]追查坏牛奶Pollutant Control
求最小割和最小割条件下最小减少的边数
可以将边权扩大为w * 1001 + 1,因为最多1000条边,所以边权依然是第一优先级,边数为第二优先级
做法2:从大到小枚举所有边,如果去掉这条边之后的最大流减少量和边权一样,那么就需要去掉这条边
P3556 [POI2013]MOR-Tales of seafaring
预处理出两两之间到达距离的偶数最小值和奇数最小值,然后直接回答询问
但是这题空间好像不大 可以离线做