【线段树|191012CSP-J模拟题解】T2算答案加成了矩阵的一行然后调了我2个小时
T1:
求图的仅在一个简单环中的边
显然点双
Code:
#include
#define pb push_back
#define fi first
#define se second
using namespace std;
inline int read(){
int res=0,f=1;
char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-f;
ch=getchar();
}
while(isdigit(ch)) {res=(res<<1)+(res<<3)+(ch^48);
ch=getchar();
}
return res*f;
}
const int N=1000005;
int adj[N],in[N],nxt[N<<1],to[N<<1],cnt=1;
inline void addedge(int u,int v){nxt[++cnt]=adj[u],adj[u]=cnt,to[cnt]=v;
}
int dfn[N],low[N],tim,id[N],bcc,num[N],ee[N],ans[N];
int stk[N],top,n,m,vis[N];
pair E[N];
vector cir[N];
void dfs(int u,int fa){
dfn[u]=low[u]=++tim;
stk[++top]=u;
for(int e=adj[u];
e;
e=nxt[e]){
int v=to[e];
if(v==fa)continue;
if(!dfn[v]) dfs(v,u),low[u]=min(low[u],low[v]);
else {low[u]=min(low[u],dfn[v]);
continue;
}
if(low[v]>=dfn[u]){
int tmp;
bcc++;
do{
tmp=stk[top];
cir[bcc].pb(tmp);
num[bcc]++;
top--;
}while(tmp!=v);
cir[bcc].pb(u);
num[bcc]++;
}
}
}
inline void file(){freopen("graph.in","r",stdin);
freopen("graph.out","w",stdout);
}
int main(){
n=read(),m=read();
for(int i=1;
i<=m;
i++){
int u=read(),v=read();
E[i].fi=u,E[i].se=v;
addedge(u,v),addedge(v,u);
}
dfs(1,0);
for(int i=1;
i<=bcc;
i++){
for(int j=0;
jdfn[v]){ee[i]++;
ans[i]^=e>>1;
}
}
}
}
int res=0;
for(int i=1;
i<=bcc;
i++) if(ee[i]==num[i])res^=ans[i];
cout<
T2:求长度为n的最大价值的串,串中每出现一个给定子串价值会加上一个对应的给定值
串总和200,n规模1e12
显然矩阵快速幂优化AC自动机上DP
Code:
#include
#define pb push_back
#define mp make_pair
#define ll long long
#define fi first
#define se second
#define db double
using namespace std;
inline ll read(){
ll res=0,f=1;
char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-f;
ch=getchar();
}
while(isdigit(ch)) {res=(res<<1)+(res<<3)+(ch^48);
ch=getchar();
}
return res*f;
}
const int N=205,M=201;
const ll INF=1e18;
int cnt=0;
struct Mat{
ll a[M][M];
inline void init(){
for(int i=0;
i<=cnt;
++i)
for(int j=0;
j<=cnt;
++j) a[i][j]=-INF;
}
inline Mat operator * (const Mat &b)const{
Mat res;
res.init();
for(int i=0;
i<=cnt;
++i)
for(int k=0;
k<=cnt;
++k) if(a[i][k]!=-INF)
for(int j=0;
j<=cnt;
++j) if(b.a[k][j]!=-INF)
res.a[i][j]=max(res.a[i][j],a[i][k]+b.a[k][j]);
return res;
}
}trans,bs;
inline Mat ksm(Mat a,ll b){
Mat res=a;
for(;
b;
b>>=1,a=a*a) if(b&1) res=res*a;
return res;
}
char s[N];
namespace ACAM{
struct trie{
int son[26];
ll val;
}tr[N*10];
inline void ins(int len,ll w){
int now=0;
for(int i=1;
i<=len;
i++){
if(!tr[now].son[s[i]-'a']) tr[now].son[s[i]-'a']=++cnt;
now=tr[now].son[s[i]-'a'];
}
tr[now].val+=w;
}
int fail[N*10];
inline void buildfail(){
queueq;
for(int i=0;
i<26;
i++) if(tr[0].son[i]) q.push(tr[0].son[i]);
while(!q.empty()){
int x=q.front();
q.pop();
for(int i=0;
i<26;
i++){
if(tr[x].son[i]) fail[tr[x].son[i]]=tr[fail[x]].son[i],q.push(tr[x].son[i]),tr[tr[x].son[i]].val+=tr[fail[tr[x].son[i]]].val;
else tr[x].son[i]=tr[fail[x]].son[i];
}
}
}
inline void buildmartix(){
for(int i=0;
i<=cnt;
i++)
for(int j=0;
j<26;
j++) trans.a[tr[i].son[j]][i]=tr[tr[i].son[j]].val;
}
}
using namespace ACAM;
ll a[N];
inline void file(){freopen("string.in","r",stdin);
freopen("string.out","w",stdout);
}
int main(){
ll n=read();
int m=read();
for(int i=1;
i<=m;
i++) a[i]=read();
for(int i=1;
i<=m;
i++){
scanf("%s",s+1);
int len=strlen(s+1);
ins(len,a[i]);
}
buildfail();
trans.init();
buildmartix();
trans=ksm(trans,n-1);
ll ans=0;
for(int i=0;
i
T3:有n个位置,某些位置有初始数,再给出m个限制,形如 [ l , r ] [l,r] [l,r]中有k个位置的数严格大于这个区间的其他数,求合法解或者无解,给出的位置总和不超过3e5,位置不超过1e5,限制不超过2e5
显然线段树优化建图+拓扑排序
Code:
#include
#define pb push_back
#define mp make_pair
#define ll long long
#define fi first
#define se second
#define db double
using namespace std;
inline int read(){
int res=0,f=1;
char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-f;
ch=getchar();
}
while(isdigit(ch)) {res=(res<<1)+(res<<3)+(ch^48);
ch=getchar();
}
return res*f;
}
const int N=5e6+5;
int n;
int p[N<<1],val[N],a[N];
int vis[N<<1],head[N],nxt[N<<1],tot=0,c[N<<1],in[N];
inline void add(int x,int y,int z){in[y]++;
vis[++tot]=y;
c[tot]=z;
nxt[tot]=head[x];
head[x]=tot;
}
int cnt=0;
inline void build(int k,int l,int r){
if(l==r){p[k]=l;
return;
}
p[k]=++cnt;
int mid=l+r>>1;
build(k<<1,l,mid),build(k<<1|1,mid+1,r);
add(p[k<<1],p[k],0),add(p[k<<1|1],p[k],0);
}
inline void modify(int k,int l,int r,int ql,int qr,int pos){
if(ql<=l && r<=qr) return add(p[k],pos,1);
int mid=l+r>>1;
if(ql<=mid) modify(k<<1,l,mid,ql,qr,pos);
if(qr>mid) modify(k<<1|1,mid+1,r,ql,qr,pos);
}
bool f=0;
inline bool topsort(){
queueq;
for(int i=1;
i<=cnt;
i++) if(!in[i]) q.push(i);
while(!q.empty()){
int x=q.front();
q.pop();
if(val[x]>1e9 || (a[x] && val[x]>a[x])) return false;
val[x]=max(1,max(val[x],a[x]));
for(int i=head[x];
i;
i=nxt[i]){
int y=vis[i];
val[y]=max(val[y],val[x]+c[i]);
--in[y];
if(in[y]==0) q.push(y);
}
}
for(int i=1;
i<=n;
i++) if(in[i]) return false;
f=1;
return true;
}
int main(){
n=read();
cnt=n;
int s=read(),m=read();
for(int i=1;
i<=s;
i++){int x=read();
a[x]=read();
}
build(1,1,n);
while(m--){
int l=read(),r=read(),k=read();
int last=l-1,inode=++cnt;
for(int i=1;
i<=k;
i++){
int x=read();
add(inode,x,0);
if(last+1<=x-1) modify(1,1,n,last+1,x-1,inode);
last=x;
}
if(last+1<=r) modify(1,1,n,last+1,r,inode);
}
puts(topsort()?"Possible":"Impossible");
if(f) for(int i=1;
i<=n;
i++) cout<
推荐阅读
- 线段树|[类欧几里得算法 线段树] BZOJ 1938 [CROATIAN2010] ALADIN
- 牛客 C. 子段乘积(线段树)
- 牛客挑战赛39 C 牛牛的等差数列(线段树)(*)
- 牛客 数据结构(区间修改+求区间元素平方和)
- 校门外的树 线段树版
- 树链剖分|牛客练习赛51 F-ABCBA(树链剖分,线段树,状态转移)
- 数论|bzoj 1938 - 类欧几里得+线段树
- 线段树|FZU - 2277(树链剖分或dfs序+线段树)
- 并查集|[CF938G] Shortest Path Queries
- 牛客网 练习赛25 B最长区间