第二题:对于一个元素集合最大值减最小值小于等于某个值可以用单调队列来维护
第三题:
给你一张图,500000组询问询问x到y之间是否存在一条经过奇数个点的路径
这道题利用了点双连通分量的性质: 一个点双连通分量如果有一个奇环,那么你如果经过其中两个不同点就一定可以改变路径的奇偶性,这个证明比较玄学,我也不确定,我是利用一个存在奇环的点双连通分量中的一个点一定在一个奇环上来证的.(雾);奇环用二分图染色来求
然后zrf给出了一种比较好的方法来建树,对于每一个点双新建一个节点与点双中的所有点连边,这样就可以方便的判断点的出入情况了.
然而我利用dfs树也给出了一种做法,我们说其具备改变奇偶的能力,当且仅当其和其父亲均在一个有奇环的点双中,这样做能够保证不是只仅仅经过一个点.(一定有一个进点一个出点).做法比较容易.
这类构造体往往与联通分量有关,下次看到改变奇偶性要想到奇环,还有zrf做法适应普遍题目,我的算法只是一个trick.
%:pragma GCC optimize(4)
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<stack>
#include<vector>
using namespace std;
const int N = 1000005;
const int M = N * 2;
int fir[N] , ne[M] , to[M] , cnt = 1 , scc_no[N] , stk[N] , tot , depth[N] , vis[N] , dfs_clock , dfn[N] , low[N] , cut[N] , scc_cnt , col[N];
int n , m ,q , x , y , is_two[N] , can[N] , valid[N][26] , fa[N] , st[N][26];
void add(int x , int y) {
ne[++ cnt] = fir[x]; fir[x] = cnt; to[cnt] = y;
}
void link(int x, int y) {
add(x , y); add(y , x);
}
#define Foreachson(i , x) for(int i = fir[x];i;i = ne[i])
#define Pair pair<int,int>
void DFS(int x, int f) {
depth[x] = depth[f] + 1;
vis[x] = 1;
fa[x] = f;
Foreachson(i , x) {
int V = to[i];
if(vis[V]) continue;
DFS(V , x);
}
}
vector<int>scc_col[N];
vector<Pair>scc_edge[N];
vector<int>G[N];
stack<Pair>S;
void dfs(int x , int f) {
low[x] = dfn[x] = ++ dfs_clock;
int py= 0;
Foreachson(i , x) {
int V = to[i];
py ++;
if(!dfn[V]) {
S.push(make_pair(x , V));
dfs(V , x);
if(dfn[x] <= low[V]) {
cut[x] = 1;
++ scc_cnt; scc_col[scc_cnt].clear();
for(;;) {
Pair ind = S.top(); S.pop();
scc_edge[scc_cnt].push_back(ind);
int u = ind.first , v = ind.second;
if(scc_no[u] != scc_cnt) {
scc_no[u] = scc_cnt;
scc_col[scc_cnt].push_back(u);
}
if(scc_no[v] != scc_cnt) {
scc_no[v] = scc_cnt;
scc_col[scc_cnt].push_back(v);
}
if(ind == (make_pair(x , V))) break;
}
}
low[x] = min(low[x] , low[V]);
}
else if(dfn[V] < dfn[x] && V != f) {
low[x] = min(low[x] , low[V]);
S.push(make_pair(V , x));
}
}
// if(py == 1 && x== 1) cut[x] = 0;
}
int getans(int x , int Col) {
col[x] = Col;
for(int i = 0;i <(int)G[x].size();i ++) {
int V = G[x][i];
if(col[V] == Col) return 0;
if(col[V] == (Col ^ 1)) continue;
if(!getans(V , Col ^ 1)) return 0;
}
return 1;
}
void calc(int x) {
for(int i = 0;i <(int) scc_col[x].size();i ++) {
int it = scc_col[x][i];
col[it] = x * 2 - 1;
G[it].clear();
}
for(int i = 0;i <(int) scc_edge[x].size();i ++) {
Pair now = scc_edge[x][i];
G[now.first].push_back(now.second);
G[now.second].push_back(now.first);
}
for(int i = 0;i <(int) scc_col[x].size();i ++) {
int it = scc_col[x][i];
if(col[it] != x * 2 && col[it] != x * 2 + 1) {
int xxx = getans(it , x * 2);
if(!xxx) {
is_two[x] = 0;
return;
}
}
}
is_two[x] = 1;
}
void getit(void) {
for(int i = 1;i <= scc_cnt;i ++) {
calc(i);
if(!is_two[i]) {
for(int j = 0;j <(int) scc_col[i].size();j ++) {
can[scc_col[i][j]] = 1;
}
}
}
}
void dfs2(int x , int f) {
valid[x][0] = can[x] & can[f];
st[x][0] = f;
for(int i = 1;i <= 25;i ++) {
st[x][i] = st[st[x][i - 1]][i - 1];
valid[x][i] = valid[x][i - 1] | valid[st[x][i - 1]][i - 1];
}
Foreachson(i , x) {
int V = to[i];
if(fa[V] == x) {
dfs2(V , x);
}
}
}
bool get(int x , int y) {
if(depth[x] > depth[y]) swap(x , y);
int ans = 0;
for(int i = 25;i >= 0;i --) {
if(depth[st[y][i]] >= depth[x]) {
ans |= valid[y][i];
y = st[y][i];
}
}
if(x == y) return ans;
for(int i = 25;i >= 0;i --) if(st[x][i] != st[y][i]) {
ans |= valid[x][i];
ans |= valid[y][i];
x = st[x][i];
y = st[y][i];
}
ans |= valid[y][0];
ans |= valid[x][0];
return ans;
}
int main(void) {
scanf("%d%d%d",&n,&m,&q);
for(int i = 1;i <= m;i ++) {
scanf("%d%d",&x,&y); link(x , y);
}
DFS(1 , 0);
dfs(1 , 0);
getit();
dfs2(1 , 0);
for(int i = 1;i <= q;i ++) {
scanf("%d%d",&x,&y);
if((depth[x] - depth[y]) % 2 == 0 && !get(x , y)) puts("NIE");
else puts("TAK");
}
}