只会做T1,FallDream T2 n^2暴力AC,太强啦。
T1.Modern Art
题目大意:有一个n*n的矩阵,一开始都是0,你有n^2种颜色,编号1到n^2,每次可以选出一种颜色涂满一个子矩阵(如果已涂则覆盖),每种颜色有且涂一次,给定最终矩阵的颜色,问有几种颜色可能是第一个涂上去的。(n<=1000)
思路:我们把最终每种颜色的最左最右最上最下当作这种颜色的边界,如果一种颜色的某个格子在超过1个边界内(即在除了自己颜色所在的边界的边界),那么这种颜色不可能是第一个涂的,二维前缀和解决即可,复杂度O(n^2)。
#include<cstdio> #include<algorithm> #include<vector> using namespace std; inline int read() { int x;char c; while((c=getchar())<'0'||c>'9'); for(x=c-'0';(c=getchar())>='0'&&c<='9';)x=(x<<3)+(x<<1)+c-'0'; return x; } #define MN 1000 vector< pair<int,int> > v[MN*MN+5]; int f[MN+5][MN+5]; int main() { freopen("art.in","r",stdin); freopen("art.out","w",stdout); int n=read(),i,j,x,cnt=-1,x0,y0,x1,y1; for(i=1;i<=n;++i)for(j=1;j<=n;++j)if(x=read()) { if(!v[x].size())++cnt; v[x].push_back(make_pair(i,j)); } if(!cnt)return 0*printf("%d",n*n-1); for(i=1;i<=n*n;++i)if(v[i].size()) { x0=y0=1000;x1=y1=0; for(j=0;j<v[i].size();++j) x0=min(x0,v[i][j].first),y0=min(y0,v[i][j].second), x1=max(x1,v[i][j].first),y1=max(y1,v[i][j].second); ++f[x0][y0];--f[++x1][y0];--f[x0][++y1];++f[x1][y1]; } for(i=1;i<=n;++i)for(j=1;j<=n;++j)f[i][j]+=f[i-1][j]+f[i][j-1]-f[i-1][j-1]; for(i=1,cnt=0;i<=n*n;++i) { for(j=0;j<v[i].size();++j) if(f[v[i][j].first][v[i][j].second]>1)break; if(j==v[i].size())++cnt; } printf("%d",cnt); fclose(stdin);fclose(stdout);return 0; }
T2.Switch Grass
题目大意:给定一张n个点m条边的无向图,边有边权,点有颜色,q次操作,每次操作修改一个点的颜色并询问当前图中最近的两个颜色不同点的距离。(n,m,q<=200,000)
思路:首先最近的两个颜色不同点一定是相邻的点,并且一定都在这张图的最小生成树的一条边上(如果走多条边或者非最小生成树边,都容易证明必然有更优解)。先找出最小生成树,随便定个根,我们维护每个点连向他儿子的答案,可以用3种堆维护,第一种每个点对儿子的每种颜色都建一个,维护这种颜色中最近的儿子,第二种每个点建一个,维护这个点到儿子中最近的颜色和次近的颜色(若最近的颜色与该节点颜色相同则取次近作为答案),第三种维护各个点的答案,每次修改依次更新父亲的堆和答案,再更新一下自己的答案,总复杂度O(nlogn)。懒得打堆都用set代替了,结果T了一个点,发现存答案的堆可以用线段树代替,然后就过了。
#include<cstdio> #include<cstring> #include<algorithm> #include<set> #include<map> using namespace std; inline int read() { int x;char c; while((c=getchar())<'0'||c>'9'); for(x=c-'0';(c=getchar())>='0'&&c<='9';)x=(x<<3)+(x<<1)+c-'0'; return x; } #define MN 200000 #define N 262144 #define INF 0x7FFFFFFF #define p(x,y) make_pair(x,y) struct Edge{int x,y,w;}E[MN+5]; bool cmp(Edge a,Edge b){return a.w<b.w;} struct edge{int nx,t,w;}e[MN*2+5]; int f[MN+5],h[MN+5],en,c[MN+5],fa[MN+5],tf[MN+5],cnt,t[N*2+5]; set<pair<int,int> >stc[MN*2+5],stf[MN+5]; set<pair<int,int> >::iterator it; map<int,int> mp[MN+5]; int gf(int k){return f[k]?f[k]=gf(f[k]):k;} inline void ins(int x,int y,int w) { e[++en]=(edge){h[x],y,w};h[x]=en; e[++en]=(edge){h[y],x,w};h[y]=en; } inline void change(int k,int x){for(t[k+=N]=x;k>>=1;)t[k]=min(t[k<<1],t[k<<1|1]);} void dfs(int x) { int i,v; stf[x].insert(p(INF,0)); for(i=h[x];i;i=e[i].nx)if(e[i].t!=fa[x]) { fa[e[i].t]=x;tf[e[i].t]=e[i].w;dfs(e[i].t); if(v=mp[x][c[e[i].t]])stf[x].erase(p(stc[v].begin()->first,c[e[i].t])); else stc[v=mp[x][c[e[i].t]]=++cnt].insert(p(INF,0)); stc[v].insert(p(e[i].w,e[i].t)); stf[x].insert(p(stc[v].begin()->first,c[e[i].t])); } it=stf[x].begin();if(it->second==c[x])++it; change(x,it->first); } void renew(int x,int z) { if(fa[x]) { int v=mp[fa[x]][c[x]]; stf[fa[x]].erase(p(stc[v].begin()->first,c[x])); stc[v].erase(p(tf[x],x)); stf[fa[x]].insert(p(stc[v].begin()->first,c[x])); if(v=mp[fa[x]][z])stf[fa[x]].erase(p(stc[v].begin()->first,z)); else stc[v=mp[fa[x]][z]=++cnt].insert(p(INF,0)); stc[v].insert(p(tf[x],x)); stf[fa[x]].insert(p(stc[v].begin()->first,z)); it=stf[fa[x]].begin();if(it->second==c[fa[x]])++it; change(fa[x],it->first); } it=stf[x].begin();if(it->second==(c[x]=z))++it; change(x,it->first); } int main() { freopen("grass.in","r",stdin); freopen("grass.out","w",stdout); int n,m,k,q,i; n=read();m=read();k=read();q=read(); for(i=1;i<=m;++i)E[i].x=read(),E[i].y=read(),E[i].w=read(); sort(E+1,E+m+1,cmp); for(i=1;i<=m;++i)if(gf(E[i].x)!=gf(E[i].y))f[gf(E[i].x)]=gf(E[i].y),ins(E[i].x,E[i].y,E[i].w); for(i=1;i<=n;++i)c[i]=read(); memset(t,127,sizeof(t));dfs(1); while(q--)i=read(),renew(i,read()),printf("%d ",t[1]); fclose(stdin);fclose(stdout);return 0; }