算法
特殊性质
显然链的情况就是括号匹配
因此显然有代码
代码
#include <bits/stdc++.h>
#define int long long
const int MAXN = 5e5 + 20;int n;
std::string Braket;
int fa[MAXN];bool Check_Special_Quality()
{for (int i = 2; i <= n; i++){if (fa[i] != i - 1){return false;}}return true;
}std::stack<int> Pre;
int k[MAXN];
int Sum[MAXN];int calc()
{int ans = 0;for (int i = 1; i <= n; i++){// printf("%d ", k[i]);ans = ans ^ (i * Sum[i]);}return ans;
}void Solve_For_Special_Quality()
{for (int i = 1; i <= n; i++){if (Braket[i] == '('){Pre.push(i);}else if (Braket[i] == ')'){if (Pre.empty()){}else{int Now = Pre.top();Pre.pop();k[i] = k[Now - 1] + 1;}}Sum[i] = Sum[i - 1] + k[i];}printf("%lld", calc());
}signed main()
{scanf("%lld", &n);std::cin >> Braket;Braket = ' ' + Braket;for (int i = 2; i <= n; i++){scanf("%lld", &fa[i]);}if (Check_Special_Quality()){Solve_For_Special_Quality();return 0;}return 0;
}
注意不能用单数组, 因为不能计算反括号对应正括号
正解
显然有树状的递推性质
那么有
\[lst_i = lst_{t - 1} + 1 \rightarrow lst_x = lst_{\text{fa of x}} + 1
\]
代码
#include<bits/stdc++.h>
#define orz 0
#define inf 0x3f3f3f3f
#define ll long long
#define maxn 500005;using namespace std;int n;
char c[maxn];
int head[maxn], nxt[maxn], to[maxn], cnt, fa[maxn];
ll lst[maxn], sum[maxn], ans;
int s[maxn], top;void add_edge(int u, int v)
{nxt[++ cnt] = head[u];head[u] = cnt;to[cnt] = v;
}void dfs(int x)
{int tmp = 0;if(c[x] == ')'){if(top){tmp = s[top];lst[x] = lst[fa[tmp]] + 1;-- top; }}else if(c[x] == '(') s[++ top] = x; sum[x] = sum[fa[x]] + lst[x]; //如上所述 for(int i = head[x]; i; i = nxt[i])dfs(to[i]); //递归 //回溯复原操作if(tmp != 0) s[++ top] = tmp; //不为 0 代表有信息被弹出 else if(top) -- top; //为 0 代表没有弹出,如果栈不为空说明一定压入了一个信息,需要弹出这个信息复原
}int main()
{scanf("%d", &n);scanf("%s", c + 1);for(int i = 2; i <= n; i ++){int f;scanf("%d", &f);add_edge(f, i);fa[i] = f;}dfs(1);for(int i = 1; i <= n; i ++)ans ^= sum[i] * (ll)i;printf("%lld", ans);return orz;
}
ctj 是这样的
总结
特殊套路 :
dfs 时保持状态稳定