1.k个横着的障碍物(均在x轴上方),n个关健点(均在x轴上方),m个询问,问在某个坐标能看到多少个关键点(均在x轴下方)。k≤50,n,m≤100000,强制在线。
我只能说障碍物的两个端点很重要,因为它是许多关键直线的交点。这样判断一个点左侧有多少直线就只和与端点的连线的倾斜角有关了。
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long int ll; 4 const int maxn=1E5+5; 5 int n,k,op,m,lastans; 6 struct pt 7 { 8 ll x,y; 9 int num; 10 pt(ll a=0,ll b=0,int c=0):x(a),y(b),num(c){} 11 pt operator+(const pt&A){return pt(x+A.x,y+A.y);} 12 pt operator-(const pt&A){return pt(x-A.x,y-A.y);} 13 ll operator*(const pt&A){return x*A.y-y*A.x;} 14 bool operator<(const pt&A)const{return x*A.y-y*A.x<0;} 15 bool operator<=(const pt&A)const{return x*A.y-y*A.x<=0;} 16 }A[maxn],B[maxn][2]; 17 vector<pt>wait[55][2]; 18 inline void solve(int num) 19 { 20 vector<pt>V; 21 for(int i=1;i<=k;++i) 22 { 23 pt x=B[i][0]-A[num],y=B[i][1]-A[num]; 24 if(x.y>=0) 25 continue; 26 x.num=i,y.num=i+k; 27 V.push_back(x),V.push_back(y); 28 } 29 sort(V.begin(),V.end()); 30 int g=0; 31 for(int i=0;i<V.size();++i) 32 { 33 pt x=V[i]; 34 bool f1=g<0; 35 g+=x.num<=k?1:-1; 36 bool f2=g<0; 37 if(f1!=f2) 38 { 39 if(x.num<=k) 40 wait[x.num][0].push_back(x); 41 else 42 wait[x.num-k][1].push_back(x); 43 } 44 } 45 } 46 int main() 47 { 48 ios::sync_with_stdio(false); 49 cin>>n>>k>>m>>op; 50 for(int i=1;i<=n;++i) 51 cin>>A[i].x>>A[i].y; 52 for(int i=1;i<=k;++i) 53 { 54 int x,y,z; 55 cin>>x>>y>>z; 56 if(x>y) 57 swap(x,y); 58 B[i][0]=pt(x,z),B[i][1]=pt(y,z); 59 } 60 for(int i=1;i<=n;++i) 61 solve(i); 62 for(int i=1;i<=k;++i) 63 { 64 sort(wait[i][0].begin(),wait[i][0].end()); 65 sort(wait[i][1].begin(),wait[i][1].end()); 66 /* 67 cout<<"NOW "<<i<<endl; 68 for(auto p:wait[i][0]) 69 cout<<p.x<<" "<<p.y<<endl; 70 cout<<endl; 71 for(auto p:wait[i][1]) 72 cout<<p.x<<" "<<p.y<<endl; 73 cout<<endl;*/ 74 } 75 for(int i=1;i<=m;++i) 76 { 77 int x,y; 78 cin>>x>>y; 79 if(op) 80 x^=lastans,y^=lastans; 81 int g=0; 82 for(int j=1;j<=k;++j) 83 { 84 g+=(wait[j][0].size())-(lower_bound(wait[j][0].begin(),wait[j][0].end(),pt(x,y)-B[j][0])-wait[j][0].begin()); 85 g-=(wait[j][1].size())-(upper_bound(wait[j][1].begin(),wait[j][1].end(),pt(x,y)-B[j][1])-wait[j][1].begin()); 86 } 87 lastans=n-g; 88 cout<<lastans<<endl; 89 } 90 return 0; 91 }
2.每次询问区间的所有子区间的mex,要求一个log,离线。
每次固定右端点r后,记在此之前出现的数字i的最右端点为b[i],没有这个数字那么b[i]为0。为了计算所有区间[i,r]的mex,我们执行下列操作:
1.设pos=0。
2.找到最大的k,使得k>pos且b[k]<b[pos]。那么左端点在区间[b[k]+1,b[pos]]中的 区间 的mex为k。
3.重复2,直到b[pos]为0。
这相当于找到b中的一个连续下降的子序列,而每次修改b只会把一个数字变大。如果这个变大的数字在之前不存在于下降子序列中,那么没有影响。否则需要修改一个类似“阶梯”的形状。很容易知道修改的总次数是线性的。这样,我们需要支持一个能区间加法、历史所有值之和的数据结构。而历史所有值之和实际上是一次函数(例如,没有任何修改的话,对于时刻t,历史所有值之和为t*val),更关键的是,时间只会单调增(那么尽管加一个一次函数会对前面产生影响,对答案也不会产生影响)。
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long int ll; 4 const int maxn=1E6+5; 5 int n,m,a[maxn],b[maxn],pre[maxn]; 6 ll ans[maxn]; 7 ll tmin[maxn*4],tk[maxn*4],tb[maxn*4],tlast[maxn*4]; 8 ll tagk[maxn*4],tagb[maxn*4]; 9 bool chosen[maxn]; 10 struct query 11 { 12 int l,r,id; 13 bool operator<(const query&A)const 14 { 15 return r<A.r; 16 } 17 }Q[maxn]; 18 void changeDot(int l,int r,int pos,int x,int num) 19 { 20 if(l==r) 21 { 22 tmin[num]=x; 23 return; 24 } 25 int mid=(l+r)>>1; 26 if(pos<=mid) 27 changeDot(l,mid,pos,x,num<<1); 28 else 29 changeDot(mid+1,r,pos,x,num<<1|1); 30 tmin[num]=min(tmin[num<<1],tmin[num<<1|1]); 31 } 32 int find(int L,int R,int l,int r,int x,int num) 33 { 34 if(l==r) 35 { 36 if(tmin[num]>x) 37 return -1; 38 return l; 39 } 40 int mid=(l+r)>>1; 41 if(L<=l&&r<=R) 42 { 43 if(tmin[num<<1]<=x) 44 return find(L,R,l,mid,x,num<<1); 45 return find(L,R,mid+1,r,x,num<<1|1); 46 } 47 if(R<=mid) 48 return find(L,R,l,mid,x,num<<1); 49 else if(mid<L) 50 return find(L,R,mid+1,r,x,num<<1|1); 51 int y=find(L,R,l,mid,x,num<<1); 52 if(y==-1) 53 return find(L,R,mid+1,r,x,num<<1|1); 54 return y; 55 } 56 inline void put(int num,int l,int r,ll k,ll b) 57 { 58 tk[num]+=k*(r-l+1); 59 tb[num]+=b*(r-l+1); 60 tagk[num]+=k,tagb[num]+=b; 61 } 62 inline void pushdown(int num,int l,int r) 63 { 64 ll k=tagk[num],b=tagb[num]; 65 tagk[num]=tagb[num]=0; 66 int mid=(l+r)>>1; 67 put(num<<1,l,mid,k,b),put(num<<1|1,mid+1,r,k,b); 68 } 69 inline void pushup(int num) 70 { 71 tk[num]=tk[num<<1]+tk[num<<1|1]; 72 tb[num]=tb[num<<1]+tb[num<<1|1]; 73 } 74 void add(int L,int R,int l,int r,ll k,ll b,int num) 75 { 76 if(L<=l&&r<=R) 77 { 78 put(num,l,r,k,b); 79 return; 80 } 81 pushdown(num,l,r); 82 int mid=(l+r)>>1; 83 if(R<=mid) 84 add(L,R,l,mid,k,b,num<<1); 85 else if(mid<L) 86 add(L,R,mid+1,r,k,b,num<<1|1); 87 else 88 add(L,R,l,mid,k,b,num<<1),add(L,R,mid+1,r,k,b,num<<1|1); 89 pushup(num); 90 } 91 ll ask(int L,int R,int l,int r,int t,int num) 92 { 93 if(L<=l&&r<=R) 94 return tk[num]*t+tb[num]; 95 pushdown(num,l,r); 96 int mid=(l+r)>>1; 97 if(R<=mid) 98 return ask(L,R,l,mid,t,num<<1); 99 else if(mid<L) 100 return ask(L,R,mid+1,r,t,num<<1|1); 101 return ask(L,R,l,mid,t,num<<1)+ask(L,R,mid+1,r,t,num<<1|1); 102 } 103 inline void insert(int now,int r,int l,int t) 104 { 105 if(t==0||r==0) 106 return; 107 if(l+1>r) 108 return; 109 assert(l+1<=r); 110 add(l+1,r,1,n,t,(ll)t-(ll)t*now,1); 111 } 112 inline void solve() 113 { 114 int pos=1; 115 chosen[0]=1; 116 for(int i=0;i<=n;++i) 117 pre[i]=-1; 118 for(int i=1;i<=n;++i) 119 { 120 a[i]=min(a[i],n); 121 if(a[i]==0||chosen[a[i]]) 122 { 123 int last=b[a[i]],now=i; 124 if(pre[a[i]]!=-1) 125 insert(i,b[pre[a[i]]],last,-a[i]); 126 int x=find(a[i]+1,n+1,0,n+1,last,1); 127 insert(i,last,b[x],-x); 128 chosen[a[i]]=0; 129 b[a[i]]=i; 130 changeDot(0,n+1,a[i],i,1); 131 int y=pre[a[i]]; 132 if(y==-1) 133 y=0; 134 x=find(a[i]+1,n+1,0,n+1,b[y],1); 135 for(;b[x]>last;x=find(x+1,n+1,0,n+1,b[x],1)) 136 { 137 if(y!=-1) 138 insert(i,b[y],b[x],x); 139 chosen[x]=1; 140 pre[x]=y; 141 y=x; 142 } 143 if(y!=-1) 144 insert(i,b[y],b[x],x); 145 chosen[x]=1; 146 pre[x]=y; 147 } 148 b[a[i]]=i; 149 changeDot(0,n+1,a[i],i,1); 150 while(pos<=m&&Q[pos].r==i) 151 { 152 ans[Q[pos].id]=ask(Q[pos].l,i,1,n,i,1); 153 ++pos; 154 } 155 } 156 } 157 int main() 158 { 159 ios::sync_with_stdio(false); 160 int useless; 161 cin>>useless>>n; 162 for(int i=1;i<=n;++i) 163 cin>>a[i]; 164 cin>>m; 165 for(int i=1;i<=m;++i) 166 { 167 cin>>Q[i].l>>Q[i].r; 168 Q[i].id=i; 169 } 170 sort(Q+1,Q+m+1); 171 solve(); 172 for(int i=1;i<=m;++i) 173 cout<<ans[i]<<' '; 174 return 0; 175 }
3.问一个串的本质不同的最小表示子串。
1 #include<bits/stdc++.h> 2 #define mod1 998244353 3 #define p1 13131 4 using namespace std; 5 typedef unsigned long long ull; 6 typedef long long int ll; 7 const int maxn=1E5+5; 8 const int base=1; 9 int n; 10 int tot,a[maxn],bucket[maxn],root[maxn],ls[maxn*20],rs[maxn*20],p[maxn]; 11 ull len1[maxn],len2[maxn],t[maxn*20]; 12 inline void init() 13 { 14 len1[0]=1; 15 for(int i=1;i<=n;++i) 16 len1[i]=len1[i-1]*p1; 17 for(int i=0;i<=2000000;++i) 18 t[i]=1; 19 } 20 void change(int l,int r,int pos,int x,int&num,int pre) 21 { 22 num=++tot; 23 ls[num]=ls[pre],rs[num]=rs[pre]; 24 if(l==r) 25 { 26 t[num]=x; 27 return; 28 } 29 int mid=(l+r)>>1; 30 if(pos<=mid) 31 change(l,mid,pos,x,ls[num],ls[pre]); 32 else 33 change(mid+1,r,pos,x,rs[num],rs[pre]); 34 t[num]=(t[ls[num]]+t[rs[num]]*len1[mid-l+1]); 35 } 36 ll ask(int L,int R,int l,int r,int num) 37 { 38 if(L<=l&&r<=R) 39 return t[num]; 40 int mid=(l+r)>>1; 41 if(R<=mid) 42 return ask(L,R,l,mid,ls[num]); 43 else if(mid<L) 44 return ask(L,R,mid+1,r,rs[num]); 45 return (ask(L,R,l,mid,ls[num])+ask(L,R,mid+1,r,rs[num])*len1[mid-max(l,L)+1]); 46 } 47 int dot(int l,int r,int pos,int num) 48 { 49 if(l==r) 50 return t[num]; 51 int mid=(l+r)>>1; 52 if(pos<=mid) 53 return dot(l,mid,pos,ls[num]); 54 return dot(mid+1,r,pos,rs[num]); 55 } 56 inline int bound(int x,int y) 57 { 58 if(x>y) 59 swap(x,y); 60 int l=1,r=x,mid; 61 while(l<r) 62 { 63 mid=(l+r+1)>>1; 64 if(ask(x-mid+1,x,1,n,root[x])==ask(y-mid+1,y,1,n,root[y])) 65 l=mid; 66 else 67 r=mid-1; 68 } 69 mid=(l+r+1)>>1; 70 return mid; 71 } 72 inline bool cmp(int x,int y) 73 { 74 int len=bound(x,y); 75 if(x<y) 76 { 77 if(x==len) 78 return 1; 79 int cx=dot(1,n,x-len,root[x]); 80 int cy=dot(1,n,y-len,root[y]); 81 return cx<cy; 82 } 83 else 84 { 85 if(y==len) 86 return 0; 87 int cx=dot(1,n,x-len,root[x]); 88 int cy=dot(1,n,y-len,root[y]); 89 return cx<cy; 90 } 91 } 92 inline void out(int x) 93 { 94 for(int j=1;j<=n-x;++j) 95 cout<<" "; 96 for(int j=1;j<=x;++j) 97 cout<<dot(1,n,j,root[x])<<" ";cout<<endl; 98 } 99 int main() 100 { 101 // freopen("waterflow7_0.in","r",stdin); 102 ios::sync_with_stdio(false); 103 cin>>n; 104 init(); 105 for(int i=1;i<=n;++i) 106 cin>>a[i]; 107 for(int i=1;i<=n;++i) 108 { 109 change(1,n,i,0+base,root[i],root[i-1]); 110 if(bucket[a[i]]) 111 change(1,n,bucket[a[i]],i-bucket[a[i]]+base,root[i],root[i]); 112 bucket[a[i]]=i; 113 } 114 for(int i=1;i<=n;++i) 115 p[i]=i; 116 stable_sort(p+1,p+n+1,cmp); 117 ll ans=p[1]; 118 for(int i=2;i<=n;++i) 119 ans+=p[i]-bound(p[i-1],p[i]); 120 cout<<ans<<endl; 121 return 0; 122 }